2009-05-14 11 views
37

Me parece que no puede encontrar una manera más eficiente "copiar" un recurso incrustado en el disco, a las siguientes:Escribir archivo de secuencia de recursos de montaje en el disco

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

parece que hay no más directa manera de hacer la copia, a menos que me falta algo ...

+2

Me parece bien. ¿Se siente como demasiadas líneas de código? – Cheeso

+0

Parece que debería haber una manera más directa que fragmentar. – user7116

Respuesta

61

no estoy seguro de por qué estás usando BinaryReader/BinaryWriter en al l. En lo personal me gustaría empezar con un método de utilidad útil:

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

luego llamarlo:

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

Usted puede cambiar el tamaño del búfer, por supuesto, o tenerlo como un parámetro para el método - pero el punto principal es que este es código más simple. ¿Es más eficiente? Nop. ¿Está seguro de que realmente necesitan este código para ser más eficiente? ¿De verdad tiene cientos de megabytes que necesita para escribir en el disco?

Me parece que rara vez se necesita el código para ser ultra-eficiente, pero casi siempre lo necesito para ser simple. El tipo de diferencia en el rendimiento que se pueden ver entre este y un enfoque "inteligente" (si uno es aún disponibles) no es probable que sea un efecto de cambio de complejidad (por ejemplo, O (n) a O (log n)) - y eso es el tipo de ganancia en el rendimiento que realmente puede valer la pena perseguir.

EDIT: Como se señaló en los comentarios, .NET 4.0 tiene Stream.CopyTo por lo que no tienen que codificar esta usted mismo.

+0

Glorioso, creo que he sido presa de ignorar la clase Stream. Pobre, pobre Stream. – user7116

+0

El archivo en cuestión está entre 5-10MB, por lo que es insignificante en términos de velocidad.Estaba buscando algo que fuera simple/conciso (ya que simple/conciso tiende a significar eficiente). – user7116

+0

Traté de cambiar a CopyTo(), y encontré una gran cantidad de "El proceso no puede acceder al archivo porque está siendo utilizado por otro proceso". errores de ASP.NET (porque el flujo todavía está abierto). Volví a usar los usos para aclarar eso. – eduncan911

2

Personalmente me gustaría hacerlo de esta manera:

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

Me gusta menos el color, pero excluyendo una forma más directa, creo que tomaré la suya como respuesta. – user7116

2

Usted tendrá que escribir un bucle, si ese es su pregunta. Pero podría prescindir del lector y el escritor, ya que el flujo básico ya se ocupa de los datos de byte [].

Esta es tan compacta como puedo conseguir:

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

Si el recurso (archivo) es binaria.

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

Y si el recurso (archivo) es texto.

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

¡Esta es la única respuesta razonable! Todos los demás están proporcionando construcciones absurdas con múltiples flujos, búferes y más de 10 líneas cuando esta línea hace lo mismo. – Traubenfuchs

+0

Este enfoque parece al menos incompleto. La documentación de .NET 4.0 para [File.WriteAllBytes] (https://msdn.microsoft.com/en-us/library/system.io.file.writeallbytes%28v=vs.100%29.aspx) indica que el segundo argumento es una matriz de bytes cuyo contenido debe escribirse en el archivo. Y la documentación para [File.WriteAllText] (https://msdn.microsoft.com/en-us/library/ms143375%28v=vs.100%29.aspx) indica que el segundo argumento es la cadena para escribir en el archivo. Entonces, especificar 'Resources.ResourceName' como el segundo argumento en realidad no tiene sentido. – DavidRR

+0

Si 'Resources.ResourceName' es binario, el tipo de' Resources.ResourceName' es 'Byte []' según se requiera, y funcionará como se espera. ¿Esto lo hace completo/claro para usted? – KoalaBear

14

verdad es que acabé utilizando esta sola línea: Assembly.GetExecutingAssembly().GetManifestResourceStream("[Project].[File]").CopyTo(New FileStream(FileLocation, FileMode.Create)). Por supuesto, esto es para .Net 4.0

Actualización: Encontré que la línea anterior podría mantener un archivo bloqueado de modo que SQLite informa que la base de datos es de solo lectura. Por lo tanto, terminé con lo siguiente:

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

+1, definitivamente el camino a seguir .Net 4.0+. También notaría una manera rápida de crear 'FileStream's con los métodos estáticos en el objeto' File', como ['File.Create()'] (http://msdn.microsoft.com/en-us /library/system.io.file.create.aspx). – user7116

Cuestiones relacionadas