【问题标题】:How can I extract a file from an embedded resource and save it to disk?如何从嵌入式资源中提取文件并将其保存到磁盘?
【发布时间】:2012-10-13 11:07:56
【问题描述】:

我正在尝试使用 CSharpCodeProvider 编译下面的代码。文件编译成功,但是当我点击生成的EXE文件时,出现错误(Windows正在寻找解决这个问题的方法),什么也没有发生。

当我使用 CSharpCodeProvider 编译下面的代码时,我使用这行代码将MySql.Data.dll 添加为嵌入式资源文件:

if (provider.Supports(GeneratorSupport.Resources))
    cp.EmbeddedResources.Add("MySql.Data.dll");

文件已成功嵌入(因为我注意到文件大小增加了)。

在下面的代码中,我尝试提取嵌入的 DLL 文件并将其保存到 System32,但是下面的代码由于某种原因不起作用。

namespace ConsoleApplication1
{
    class Program
    {
        public static void ExtractSaveResource(String filename, String location)
        {
            //Assembly assembly = Assembly.GetExecutingAssembly();
            Assembly a = .Assembly.GetExecutingAssembly();
            //Stream stream = assembly.GetManifestResourceStream("Installer.Properties.mydll.dll"); // or whatever
            //string my_namespace = a.GetName().Name.ToString();
            Stream resFilestream = a.GetManifestResourceStream(filename);
            if (resFilestream != null)
            {
                BinaryReader br = new BinaryReader(resFilestream);
                FileStream fs = new FileStream(location, FileMode.Create); // Say
                BinaryWriter bw = new BinaryWriter(fs);
                byte[] ba = new byte[resFilestream.Length];
                resFilestream.Read(ba, 0, ba.Length);
                bw.Write(ba);
                br.Close();
                bw.Close();
                resFilestream.Close();
            }
            // this.Close();
        }

        static void Main(string[] args)
        {
            try
            {
                string systemDir = Environment.SystemDirectory;
                ExtractSaveResource("MySql.Data.dll", systemDir);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.ReadKey();
            }
        }
    }
}

如何提取作为资源嵌入的 DLL 文件并将其保存到 System32?

【问题讨论】:

  • Rafik,你应该在下面查看 Thomas Sapp 的答案,因为它绝对比你接受的要好。

标签: c# .net embedded-resource csharpcodeprovider


【解决方案1】:

我建议做起来更轻松。我假设资源存在并且文件是可写的(如果我们谈论的是系统目录,这可能是一个问题)。

public void WriteResourceToFile(string resourceName, string fileName)
{
    using(var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
    {
        using(var file = new FileStream(fileName, FileMode.Create, FileAccess.Write))
        {
            resource.CopyTo(file);
        } 
    }
}

【讨论】:

  • 值得一提的是这需要 .NET 4.0 或更高版本
  • 嵌入式资源文件的资源名称是什么?
  • 回答我自己的问题:Namespace.Path.To.File.FileName 例如:ConsoleApp1.Stuff.File1.xml
  • 它实际上是可配置的。您可以在资源的首选项窗口中更改名称(或直接在 csproj 文件中)
【解决方案2】:

我发现最简单的方法是使用Properties.ResourcesFile。这是我使用的代码(需要using System.IO)...

对于二进制文件: File.WriteAllBytes(fileName, Properties.Resources.file);

对于文本文件: File.WriteAllText(fileName, Properties.Resources.file);

【讨论】:

  • 这从 Visual Studio 2005 / .Net 2.0 开始有效!我不知道是什么证明了 2012 年的答案:P
  • 需要您先创建一个资源文件...可能对逐步将文件放入其中等有用。
  • 这绝对是完美的答案。
  • 很好的答案。只是会添加您可能需要像这样为您的 ProjectNameSpace 添加前缀属性: ProjectNamespace.Properties.Resources.yourfilename
  • 这不是完美的答案,因为它没有解释项目资源的来源,对于可能正在关注这个的新手。先看这里>>stackoverflow.com/a/90699然后使用这个答案
【解决方案3】:

我一直在使用这个(经过测试的)方法:

OutputDir:要复制资源的位置

ResourceLocation:命名空间(+ 目录名)

文件:资源位置内的文件列表,您要复制。

    private static void ExtractEmbeddedResource(string outputDir, string resourceLocation, List<string> files)
    {
        foreach (string file in files)
        {
            using (System.IO.Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceLocation + @"." + file))
            {
                using (System.IO.FileStream fileStream = new System.IO.FileStream(System.IO.Path.Combine(outputDir, file), System.IO.FileMode.Create))
                {
                    for (int i = 0; i < stream.Length; i++)
                    {
                        fileStream.WriteByte((byte)stream.ReadByte());
                    }
                    fileStream.Close();
                }
            }
        }
    }

【讨论】:

    【解决方案4】:

    这很好用!

    public static void Extract(string nameSpace, string outDirectory, string internalFilePath, string resourceName)
    {
        //nameSpace = the namespace of your project, located right above your class' name;
        //outDirectory = where the file will be extracted to;
        //internalFilePath = the name of the folder inside visual studio which the files are in;
        //resourceName = the name of the file;
        Assembly assembly = Assembly.GetCallingAssembly();
    
        using (Stream s = assembly.GetManifestResourceStream(nameSpace + "." + (internalFilePath == "" ? "" : internalFilePath + ".") + resourceName))
        using (BinaryReader r = new BinaryReader(s))
        using (FileStream fs = new FileStream(outDirectory + "\\" + resourcename, FileMode.OpenOrCreate))
        using (BinaryWriter w = new BinaryWriter(fs))
        {
            w.Write(r.ReadBytes((int)s.Length));
        }
    }
    

    使用示例:

    public static void ExtractFile()
    {
        String local = Environment.CurrentDirectory; //gets current path to extract the files
    
        Extract("Geral", local, "Arquivos", "bloquear_vbs.vbs");
    }    
    

    如果这仍然没有帮助,试试这个视频:https://www.youtube.com/watch?v=_61pLVH2qPk

    【讨论】:

      【解决方案5】:

      或者使用扩展方法...

       /// <summary>
       /// Retrieves the specified [embedded] resource file and saves it to disk.  
       /// If only filename is provided then the file is saved to the default 
       /// directory, otherwise the full filepath will be used.
       /// <para>
       /// Note: if the embedded resource resides in a different assembly use that
       /// assembly instance with this extension method.
       /// </para>
       /// </summary>
       /// <example>
       /// <code>
       ///       Assembly.GetExecutingAssembly().ExtractResource("Ng-setup.cmd");
       ///       OR
       ///       Assembly.GetExecutingAssembly().ExtractResource("Ng-setup.cmd", "C:\temp\MySetup.cmd");
       /// </code>
       /// </example>
       /// <param name="assembly">The assembly.</param>
       /// <param name="resourceName">Name of the resource.</param>
       /// <param name="fileName">Name of the file.</param>
       public static void ExtractResource(this Assembly assembly, string filename, string path=null)
       {
           //Construct the full path name for the output file
           var outputFile = path ?? $@"{Directory.GetCurrentDirectory()}\{filename}";
      
           // If the project name contains dashes replace with underscores since 
           // namespaces do not permit dashes (underscores will be default to).
           var resourceName = $"{assembly.GetName().Name.Replace("-","_")}.{filename}";
      
           // Pull the fully qualified resource name from the provided assembly
           using (var resource = assembly.GetManifestResourceStream(resourceName))
           {
               if (resource == null)
                   throw new FileNotFoundException($"Could not find [{resourceName}] in {assembly.FullName}!");
      
               using (var file = new FileStream(outputFile, FileMode.Create, FileAccess.Write))
               {
                   resource.CopyTo(file);
               }
           }
       }
      

      【讨论】:

        【解决方案6】:

        尝试将您的目标程序集读入MemoryStream,然后像这样保存到FileStream(请记住,此代码未经测试):

        //Imports
        using System;
        using System.IO;
        using System.Reflection;
        
            Assembly assembly = Assembly.GetExecutingAssembly();
            using (var target = assembly.GetManifestResourceStream("MySql.Data.dll"))
            {
                var size = target.CanSeek ? Convert.ToInt32(target.Length) : 0;
        
                // read your target assembly into the MemoryStream
                MemoryStream output = null;
                using (output = new MemoryStream(size))
                {
                    int len;
                    byte[] buffer = new byte[2048];
        
                    do
                    {
                        len = target.Read(buffer, 0, buffer.Length);
                        output.Write(buffer, 0, len);
                    } 
                    while (len != 0);
                }
        
                // now save your MemoryStream to a flat file
                using (var fs = File.OpenWrite(@"c:\Windows\System32\MySql.Data.dll"))
                {
                    output.WriteTo(fs);
                    fs.Flush();
                    fs.Close();
                }
            }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-23
          • 2012-05-11
          • 1970-01-01
          • 1970-01-01
          • 2010-10-26
          相关资源
          最近更新 更多