2009-05-14 14 views
37

Ich kann nicht scheinen, um eine effizientere Art und Weise zu „kopieren“ eine eingebetteten Ressource auf Platte zu finden, als die folgenden:Write-Datei von der Montage Ressource Strom auf der Festplatte

using (BinaryReader reader = new BinaryReader(
    assembly.GetManifestResourceStream(@"Namespace.Resources.File.ext"))) 
{ 
    using (BinaryWriter writer 
     = new BinaryWriter(new FileStream(path, FileMode.Create))) 
    { 
     long bytesLeft = reader.BaseStream.Length; 
     while (bytesLeft > 0) 
     { 
      // 65535L is < Int32.MaxValue, so no need to test for overflow 
      byte[] chunk = reader.ReadBytes((int)Math.Min(bytesLeft, 65536L)); 
      writer.Write(chunk); 

      bytesLeft -= chunk.Length; 
     } 
    } 
} 

Es scheint zu sein, nicht mehr direkt Weg, um die Kopie zu tun, es sei denn ich etwas fehlt bin ...

+2

Es sieht gut aus für mich. Fühlt es sich an wie zu viele Codezeilen? – Cheeso

+0

Es fühlt sich an, als sollte es einen direkteren Weg geben als Chunking. – user7116

Antwort

61

ich bin nicht sicher, warum Sie verwenden BinaryReader/BinaryWriter et al l. Persönlich würde ich mit einer nützlichen Dienstprogramm Methode beginnen:

public static void CopyStream(Stream input, Stream output) 
{ 
    // Insert null checking here for production 
    byte[] buffer = new byte[8192]; 

    int bytesRead; 
    while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0) 
    { 
     output.Write(buffer, 0, bytesRead); 
    } 
} 

dann nennen:

using (Stream input = assembly.GetManifestResourceStream(resourceName)) 
using (Stream output = File.Create(path)) 
{ 
    CopyStream(input, output); 
} 

Sie können die Puffergröße natürlich ändern, oder haben sie als Parameter an die Methode - aber der Hauptpunkt ist, dass dies einfacher Code ist. Ist es effizienter? Nee. Sind Sie sicher, dass Sie wirklich benötigen diesen Code effizienter zu sein? Haben Sie tatsächlich Hunderte von Megabyte, die Sie auf Festplatte schreiben müssen?

Ich finde, ich brauche selten Code, um ultra-effizient zu sein, aber ich brauche es fast immer einfach zu sein. Die Art von Leistungsunterschieden, die Sie zwischen diesem und einem "cleveren" Ansatz sehen können (falls überhaupt verfügbar), ist wahrscheinlich kein komplexitätsändernder Effekt (zB O (n) zu O (log n)) - und das ist die Art der Leistungssteigerung, die wirklich wert sein kann, zu jagen.

BEARBEITEN: Wie in den Kommentaren erwähnt, hat .NET 4.0 Stream.CopyTo, so dass Sie dies nicht selbst programmieren müssen.

+0

Glorreich, ich glaube, ich bin der Ignorierung der Stream-Klasse zum Opfer gefallen. Schlechter, schlechter Strom. – user7116

+0

Die fragliche Datei ist zwischen 5-10 MB, so dass es in Bezug auf die Geschwindigkeit vernachlässigbar ist.Ich war auf der Suche nach etwas, das einfach/prägnant war (da einfach/prägnant eher effizient ist). – user7116

+0

Ich habe versucht, zu CopyTo() zu wechseln, und stieß auf eine Menge von "Der Prozess kann nicht auf die Datei zugreifen, weil sie von einem anderen Prozess verwendet wird." Fehler von ASP.NET (weil der Stream noch geöffnet ist). Ich ging zurück, um den Gebrauch zu benutzen, um das aufzuräumen. – eduncan911

2

persönlich würde ich es auf diese Weise tun:

using (BinaryReader reader = new BinaryReader(
    assembly.GetManifestResourceStream(@"Namespace.Resources.File.ext"))) 
{ 
    using (BinaryWriter writer 
     = new BinaryWriter(new FileStream(path, FileMode.Create))) 
    { 
     byte[] buffer = new byte[64 * 1024]; 
     int numread = reader.Read(buffer,0,buffer.Length); 

     while (numread > 0) 
     { 
      writer.Write(buffer,0,numread); 
      numread = reader.Read(buffer,0,buffer.Length); 
     } 

     writer.Flush(); 
    } 
} 
+0

Ich mag das minus den Flush, aber einen direkteren Weg ausgeschlossen, ich denke, ich werde deine als die Antwort nehmen. – user7116

2

Sie müssen eine Schleife schreiben, wenn das Ihre Frage ist. Aber man könnte auf den Reader und Writer verzichten, da der Basic Stream bereits mit byte [] Daten arbeitet.

Das ist etwa so kompakt wie ich bekommen kann:

using (Stream inStream = File.OpenRead(inputFile)) 
using (Stream outStream = File.OpenWrite(outputFile)) 
{ 
    int read; 
    byte[] buffer = new byte[64 * 1024]; 

    while ((read = inStream.Read(buffer, 0, buffer.Length)) > 0) 
    { 
     outStream.Write(buffer, 0, read); 
    } 
} 
49

Wenn die Ressource (Datei) binär ist.

File.WriteAllBytes("C:\ResourceName", Resources.ResourceName); 

Und wenn die Ressource (Datei) ist Text.

File.WriteAllText("C:\ResourceName", Resources.ResourceName); 
+4

Dies ist die einzig vernünftige Antwort! Jeder andere liefert absurde Konstrukte mit mehreren Streams, Puffern und mehr als 10 Zeilen, wenn diese eine Zeile das gleiche tut. – Traubenfuchs

+0

Dieser Ansatz sieht zumindest unvollständig. Die .NET 4.0-Dokumentation für [File.WriteAllBytes] (https://msdn.microsoft.com/en-us/library/system.io.file.writeallbytes%28v=vs.100%29.aspx) gibt an, dass die zweite Argument ist ein Byte-Array, dessen Inhalt in die Datei geschrieben werden soll. Und die Dokumentation für [File.WriteAllText] (https://msdn.microsoft.com/en-us/library/ms143375%28v=vs.100%29.aspx) gibt an, dass das zweite Argument die Zeichenfolge ist, in die geschrieben werden soll Datei. Daher ist die Angabe von Resources.ResourceName als zweites Argument nicht sinnvoll. – DavidRR

+0

Wenn 'Resources.ResourceName' binär ist, ist der Typ von' Resources.ResourceName' 'Byte []' wie erforderlich und funktioniert wie erwartet. Ist dies für Sie vollständig/klar? – KoalaBear

14

Ich landete tatsächlich diese einzelne Zeile mit bis: Assembly.GetExecutingAssembly().GetManifestResourceStream("[Project].[File]").CopyTo(New FileStream(FileLocation, FileMode.Create)). Natürlich ist dies für .Net 4.0

Update: Ich habe festgestellt, dass die Zeile oben möglicherweise eine Datei gesperrt, so dass SQLite meldet, dass die Datenbank schreibgeschützt ist. Daher endete ich mit dem folgenden:

Using newFile As Stream = New FileStream(FileLocation, FileMode.Create) 
    Assembly.GetExecutingAssembly().GetManifestResourceStream("[Project].[File]").CopyTo(newFile) 
End Using 
+3

+1, definitiv der Weg zu gehen .Net 4.0+. Ich würde auch einen schnellen Weg zum Erstellen von 'FileStream's mit den statischen Methoden auf dem' File' Objekt, wie ['File.Create()'] (http://msdn.microsoft.com/en-us), notieren /library/system.io.file.create.aspx). – user7116

Verwandte Themen