以编程方式加载嵌入式资源文件

时间:2015-05-29 17:38:17

标签: c# embedded-resource system-codedom-compiler

我最近实现了以下代码,以便以编程方式构建项目/ exe。在这个exe版本中,我想存储一堆"实际文件"在资源内部,作为流。

以下是我如何将文件添加到资源文件中(单数),然后将该资源文件嵌入到编译器参数中:

        List<string> UserFiles = new List<string>();
        UserFiles.AddRange(Helpers.GetFilesInFolder(this.txt_Publish_Folder.Text));

        string folder = this.txt_Package_Location.Text;
        folder = folder + "\\Package_" + DateTime.Now.ToLongTimeString().Replace(":", "_").Replace(".", "_");
        Directory.CreateDirectory(folder);

        CompilerParameters parameters = new CompilerParameters();
        parameters.GenerateExecutable = true;
        parameters.IncludeDebugInformation = true;
        parameters.GenerateInMemory = false;
        parameters.WarningLevel = 3;
        parameters.CompilerOptions = "/optimize";
        parameters.OutputAssembly = folder + "\\Install_" + this.txt_AppName.Text + ".exe";
        parameters.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
        parameters.ReferencedAssemblies.Add("System.dll");
        parameters.ReferencedAssemblies.Add("System.Core.dll");
        parameters.ReferencedAssemblies.Add("System.Data.dll");
        parameters.ReferencedAssemblies.Add("System.Data.DataSetExtensions.dll");
        parameters.ReferencedAssemblies.Add("System.Xml.dll");
        parameters.ReferencedAssemblies.Add("System.Xml.Linq.dll");

        CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp");
        if (codeProvider.Supports(GeneratorSupport.Resources))
        {
            string temp = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());
            //create temp file first, because we want to append to it so as to have a single resource file with multiple stream entries...
            File.WriteAllText(temp, null);
            for (int i = 0; i < UserFiles.Count; i++ )
            {
                byte[] FileBytes = File.ReadAllBytes(UserFiles[i]);

                using (FileStream stream = new FileStream(temp, FileMode.Append))
                {
                    using (ResourceWriter writer = new ResourceWriter(stream))
                    {
                        writer.AddResource(Path.GetFileName(UserFiles[i]), FileBytes);
                    }
                }
            }
            parameters.EmbeddedResources.Add(temp);
        }

        CompilerResults res = codeProvider.CompileAssemblyFromFile(parameters, @"C:\HIDDENPATH\Program.cs");

这很好用,不会产生任何错误,我实际上可以通过下面的代码在我构建的控制台应用程序(上面引用的Prorgam.cs)中获取嵌入式资源文件。我遇到的问题是&#34; Loading&#34;这个资源文件进入应用程序程序集/以某种方式获取其值...这是我到目前为止所做的代码:

    static void Main(string[] args)
    {
        Console.WriteLine("Checking for resources... please wait...");

        Assembly thisExe;
        thisExe = Assembly.GetExecutingAssembly();
        List<string> resources = thisExe.GetManifestResourceNames().ToList();

        if(resources.Count >= 1)
        {
            try
            {
                string baseName = resources[0];
                ResourceManager mgr = new ResourceManager(baseName, thisExe);
                Console.WriteLine("retrieved manager...");
                Console.ReadLine();
                ResourceSet set = mgr.GetResourceSet(Thread.CurrentThread.CurrentCulture, true, true);
                int count = set.Cast<object>().Count();
                Console.WriteLine("Found [" + count.ToString() + "] embedded resources. Would you like to enumerate them?");
                ConsoleKeyInfo input = Console.ReadKey();
                if (input.Key == ConsoleKey.Y)
                {
                    // Build the string of resources.
                    foreach (string resource in resources)
                        Console.WriteLine(resource);
                }

            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
                Console.ReadLine();
            }
        }

        Console.ReadLine();
    }

每当我运行构建的exe时,我得到以下结果:


Checking for resources... please wait...
retrieved manager...

Could not find any resources appropriate for the specified culture or the neutral culture.  Make sure "tmpCC59.tmp.resources" was correctly embedded or linked into assembly "Install_testing" at compile time, or that all the satellite assemblies required are loadable and fully signed.

有人可以告诉我为什么会这样吗?我已经尝试过所有可以想到的不同文化背景,但仍然没有任何结果。问题与我如何嵌入&#34;或者我如何&#34;加载&#34; ?

1 个答案:

答案 0 :(得分:2)

好的伙计们,所以这就是我最终解决的问题,这实际上解决了我所有的问题。

  1. 而不是尝试添加&#34;资源条目&#34;现在,我直接从源文件中添加每个文件作为自己的资源(不知道我为什么要制作原始文件的临时副本,而不是单独的资源文件&#34;使用流是必要的,但它不是这样的:

            for (int i = 0; i < WebAppFiles.Count; i++)
            {
                parameters.EmbeddedResources.Add(WebAppFiles[i]);
            }
    
  2. 然后,什么时候提取实际文件,而不是尝试加载&#34;设置&#34;从单个&#34;资源文件&#34;,我只是从每个嵌入资源中提取数据,如下所示:

                    for (int i = 0; i < resources.Count; i++)
                    {
                        Console.WriteLine("Extracting file: " + resources[i] + "...");
                        Stream stream = thisExe.GetManifestResourceStream(resources[i]);
                        byte[] bytes = new byte[(int)stream.Length];
                        stream.Read(bytes, 0, bytes.Length);
                        File.WriteAllBytes(dir + resources[i], bytes);
                    }
    
  3. 这种新方式基本上意味着你告诉编译器&#34;这些文件是exe所必需的并且是嵌入式的#34;所以当你调用&#34; build&#34;命令,它实际上为您完成所有工作,并以字节数组的形式读取文件并将其嵌入到可执行文件中。

    然后,另一方面,您只需告诉程序您希望使用自己的文件名将嵌入资源保存为文件。

    希望这可以帮助那些试图做到这一点的其他人...因为这类问题的每一个其他帖子都有一些过于复杂的答案,这些答案要么不完整(例如:如何嵌入,而不是检索)或者没有#39实际上是工作。