2012-10-23 19 views
32

Próbuję skompilować poniższy kod za pomocą CSharpCodeProvider. Plik został pomyślnie skompilowany, ale po kliknięciu wygenerowanego pliku EXE pojawia się błąd (system Windows szuka rozwiązania tego problemu) i nic się nie dzieje.Jak mogę wyodrębnić plik z osadzonego zasobu i zapisać go na dysku?

Kiedy skompilować kod poniżej używając CSharpCodeProvider, Dodałem MySql.Data.dll jako plik zasobów osadzonych za pomocą poniższego wiersza kodu:

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

Plik został pomyślnie osadzone (bo zauważyłem, że rozmiar pliku wzrósł).

W poniższym kodzie próbuję wyodrębnić osadzony plik DLL i zapisać go w systemie System32, ale poniższy kod nie działa z jakiegoś powodu.

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

Jak mogę wyodrębnić plik DLL, który jest osadzony jako zasób i zapisać go w systemie System32?

+0

Rafik, ty powinien przejrzeć odpowiedzi Thomasa Sappa poniżej, ponieważ jest absolutnie lepszy od tego, który zaakceptowałeś. – motoDrizzt

Odpowiedz

31

I odkryli, że najprostszym sposobem, aby to zrobić jest użycie Properties.Resources i File. Oto kod używam ...

Dla plików binarnych: File.WriteAllBytes(fileName, Properties.Resources.file);

plików tekstowych: File.WriteAllText(fileName, Properties.Resources.file);

+6

Tak prosty. To powinna być zaakceptowana odpowiedź. –

+1

A to działa od Visual Studio 2005/.Net 2.0! Nie wiem, co usprawiedliwia odpowiedź z 2012 roku: P –

+0

Potrzebuję najpierw utworzyć plik zasobów ... może być przydatny do przechodzenia przez umieszczanie plików tam, itp. –

0

Spróbuj przeczytać swój zespół docelowy w MemoryStream a następnie zapisać do FileStream tak (proszę pamiętać, że kod ten nie został przetestowany):

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

Używam tego (testowane) metoda:

OutputDir: lokalizację, w której chcesz skopiować zasobu

ResourceLocation Przestrzeń nazw (+ dirnames)

Pliki: lista plików w resourcelocation, którą chcesz skopiować.

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

Proponuję zrobić to łatwiej. Zakładam, że zasób istnieje i plik jest zapisywalny (może to być problem, jeśli mówimy o katalogach systemowych).

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

Warto o tym wspomnieć .NET 4.0 lub wyżej –

1

To działa idealnie!

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

Przykład użycia:

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

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

Jeśli to nie pomoże, spróbuj tego wideo na: https://www.youtube.com/watch?v=_61pLVH2qPk

0

lub przy użyciu metody rozszerzenie ...

/// <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 ?? [email protected]"{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); 
     } 
    } 
} 
Powiązane problemy