How can I extract a file from an embedded resource and save it to disk?
Asked Answered
N

8

67

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.

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:

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.

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?

Narcotism answered 23/10, 2012 at 13:40 Comment(0)
D
76

I have found that the easiest way to do this is to use Properties.Resources and File. Here is the code I use (requires using System.IO)...

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

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

Duad answered 7/1, 2016 at 20:29 Comment(5)
And this works since Visual Studio 2005 / .Net 2.0 ! I don't know what justifies the answers of 2012 :PCommute
Needs you to create a resources file first... might be useful to walk through putting files in there, etc.Turbid
This is absolutely the perfect answer.Jefferson
Great answer. Just would add you may need to prefix Properties with your ProjectNameSpace like this: ProjectNamespace.Properties.Resources.yourfilenameChastise
It's not the perfect answer because it doesn't explain where project resources come from, for newbies that may be looking at this. See here first >> stackoverflow.com/a/90699 THEN use this answerHypothetical
M
91

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);
        } 
    }
}
Mccann answered 14/11, 2013 at 15:48 Comment(4)
Worth mentioning this requires .NET 4.0 or aboveTurbid
What would the resourceName be for an file that's Embedded Resource?Scathe
To answer my own question: Namespace.Path.To.File.FileName E.g: ConsoleApp1.Stuff.File1.xmlScathe
It's actually configurable. You can change the name in the resource's preferences window (or directly in the csproj file)Mccann
D
76

I have found that the easiest way to do this is to use Properties.Resources and File. Here is the code I use (requires using System.IO)...

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

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

Duad answered 7/1, 2016 at 20:29 Comment(5)
And this works since Visual Studio 2005 / .Net 2.0 ! I don't know what justifies the answers of 2012 :PCommute
Needs you to create a resources file first... might be useful to walk through putting files in there, etc.Turbid
This is absolutely the perfect answer.Jefferson
Great answer. Just would add you may need to prefix Properties with your ProjectNameSpace like this: ProjectNamespace.Properties.Resources.yourfilenameChastise
It's not the perfect answer because it doesn't explain where project resources come from, for newbies that may be looking at this. See here first >> stackoverflow.com/a/90699 THEN use this answerHypothetical
A
34

I've been using this (tested) method:

OutputDir: Location where you want to copy the resource

ResourceLocation: Namespace (+ dirnames)

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();
                }
            }
        }
    }
Antananarivo answered 25/10, 2012 at 7:55 Comment(0)
P
4

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

Psychotechnology answered 17/12, 2014 at 2:26 Comment(0)
H
3

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);
         }
     }
 }
Hurt answered 12/1, 2018 at 15:44 Comment(0)
A
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):

//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();
        }
    }
Agential answered 23/10, 2012 at 13:53 Comment(0)
E
0
string roamingfolder = System.IO.Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)).FullName
                                                                                                                 + "\\Roaming\\hah";
string roamingfile = System.IO.Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)).FullName
                                                                                                                     + "\\Roaming\\hah\\image1.jpg";
Assembly asmbly = Assembly.GetExecutingAssembly();
const string NAME = "image_open2.Resources.Billi1609482658k220y8154.jpg";
if (File.Exists(roamingfile))
    File.Delete(roamingfile);
if (!Directory.Exists(roamingfolder))
    Directory.CreateDirectory(roamingfolder);
using (Stream stream = asmbly.GetManifestResourceStream(NAME))
{
    using (FileStream fileStream = new FileStream(roamingfile, FileMode.Create))
    {
         for (int i = 0; i < stream.Length; i++)
         {
              fileStream.WriteByte((byte)stream.ReadByte());
         }
         fileStream.Close();
    }
 }
Eskilstuna answered 1/8, 2022 at 12:5 Comment(1)
As it’s currently written, your answer is unclear. Please, add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Diannadianne
P
0

No need to complicate. First, add assembly as an embedded resource.

    private void ExtractAssembly(string dll)
    {
         if (!File.Exists(dll))
             File.WriteAllBytes(dll, Resources.MyDLL);
    }

This has perfectly work for me.

Paulita answered 16/11, 2022 at 16:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.