如何从嵌入式资源中提取文件并将其保存到磁盘?

时间:2021-02-01 09:54:58

I'm trying to compile the code below using CSharpCodeProvider. The file is successfully compiled, but when I click on the generated EXE file, I get an error (Windows is searching for a solution to this problem) and nothing happens.

我正在尝试使用CSharpCodeProvider来编译下面的代码。文件被成功编译,但是当我点击生成的EXE文件时,我得到一个错误(Windows正在搜索这个问题的解决方案),什么也没有发生。

When I compile the code below using CSharpCodeProvider, I've added the MySql.Data.dll as an embedded resource file using this line of code:

当我使用CSharpCodeProvider编译下面的代码时,我已经添加了MySql.Data。dll作为一个嵌入式资源文件使用这一行代码:

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

The file is successfully embedded (because I noticed the file size increased).

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

In the code below, I try to extract the embedded DLL file and save it to System32, but the code below doesn't work for some reason.

在下面的代码中,我尝试提取嵌入的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();
            }
        }
    }
}

How can I extract the DLL file that is embedded as a resource and save it to System32?

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

6 个解决方案

#1


54  

I'd suggest doing it easier. I assume that the resource exists and the file is writable (this might be an issue if we're speaking about system directories).

我建议做得容易些。我假设资源存在,文件是可写的(如果我们讨论系统目录,这可能是一个问题)。

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);
        } 
    }
}

#2


37  

I have found that the easiest way to do this is to use Properties.Resources and File. Here is the code I use...

我发现最简单的方法就是使用属性。资源和文件。这是我使用的代码……

For Binary files: File.WriteAllBytes(fileName, Properties.Resources.file);

二进制文件:文件。WriteAllBytes(文件名,Properties.Resources.file);

For Text files: File.WriteAllText(fileName, Properties.Resources.file);

对于文本文件:文件。WriteAllText(文件名,Properties.Resources.file);

#3


31  

I've been using this (tested) method:

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

OutputDir: Location where you want to copy the resource

OutputDir:您想要复制资源的位置。

ResourceLocation: Namespace (+ dirnames)

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

Files: List of files within the resourcelocation, you want to copy.

文件:资源定位中的文件列表,您想要复制。

    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


1  

This works perfectly!

这是完美的!

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));
    }
}

Example of usage:

使用的例子:

public static void ExtractFile()
{
    String local = Environment.CurrentDirectory; //gets current path to extract the files

    Extract("Geral", local, "Arquivos", "bloquear_vbs.vbs");
}    

If this still doesn't help, try this video out: https://www.youtube.com/watch?v=_61pLVH2qPk

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

#5


1  

Or using an extension method...

或者使用扩展方法…

 /// <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


0  

Try reading your target assembly into a MemoryStream and then saving to a FileStream like this (please bear in mind that this code isn't tested):

尝试将目标程序集读入MemoryStream中,然后保存到这样的文件流中(请记住这段代码没有经过测试):

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()
    }
}

#1


54  

I'd suggest doing it easier. I assume that the resource exists and the file is writable (this might be an issue if we're speaking about system directories).

我建议做得容易些。我假设资源存在,文件是可写的(如果我们讨论系统目录,这可能是一个问题)。

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);
        } 
    }
}

#2


37  

I have found that the easiest way to do this is to use Properties.Resources and File. Here is the code I use...

我发现最简单的方法就是使用属性。资源和文件。这是我使用的代码……

For Binary files: File.WriteAllBytes(fileName, Properties.Resources.file);

二进制文件:文件。WriteAllBytes(文件名,Properties.Resources.file);

For Text files: File.WriteAllText(fileName, Properties.Resources.file);

对于文本文件:文件。WriteAllText(文件名,Properties.Resources.file);

#3


31  

I've been using this (tested) method:

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

OutputDir: Location where you want to copy the resource

OutputDir:您想要复制资源的位置。

ResourceLocation: Namespace (+ dirnames)

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

Files: List of files within the resourcelocation, you want to copy.

文件:资源定位中的文件列表,您想要复制。

    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


1  

This works perfectly!

这是完美的!

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));
    }
}

Example of usage:

使用的例子:

public static void ExtractFile()
{
    String local = Environment.CurrentDirectory; //gets current path to extract the files

    Extract("Geral", local, "Arquivos", "bloquear_vbs.vbs");
}    

If this still doesn't help, try this video out: https://www.youtube.com/watch?v=_61pLVH2qPk

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

#5


1  

Or using an extension method...

或者使用扩展方法…

 /// <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


0  

Try reading your target assembly into a MemoryStream and then saving to a FileStream like this (please bear in mind that this code isn't tested):

尝试将目标程序集读入MemoryStream中,然后保存到这样的文件流中(请记住这段代码没有经过测试):

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()
    }
}