Escribir el archivo de la secuencia de recursos del ensamblado en el disco

Parece que no puedo encontrar una forma más eficiente de “copiar” un recurso incrustado en el disco que el siguiente:

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 no hay una forma más directa de hacer la copia, a menos que me falta algo …

No estoy seguro de por qué estás usando BinaryReader / BinaryWriter . Personalmente, comenzaría con un útil método de utilidad:

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

entonces llámalo:

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

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 un código más simple . ¿Es más eficiente? Nop. ¿Estás seguro de que realmente necesitas este código para ser más eficiente? ¿De verdad tiene cientos de megabytes que necesita para escribir en el disco?

Encuentro que rara vez necesito código para ser extremadamente eficiente, pero casi siempre necesito que sea simple. El tipo de diferencia en el rendimiento que puede ver entre esto y un enfoque “inteligente” (si hay uno disponible) no es probable que sea un efecto que cambia la complejidad (por ejemplo, O (n) a O (log n)) – y ese es el tipo de ganancia de rendimiento que realmente puede valer la pena perseguir.

EDITAR: Como se menciona en los comentarios, .NET 4.0 tiene Stream.CopyTo por lo que no necesita codificarlo usted mismo.

Si el recurso (archivo) es binario.

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

Y si el recurso (archivo) es texto.

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

De hecho, terminé usando esta única línea: Assembly.GetExecutingAssembly().GetManifestResourceStream("[Project].[File]").CopyTo(New FileStream(FileLocation, FileMode.Create)) . Por supuesto, esto es para .Net 4.0

Actualización: descubrí que la línea anterior podría mantener un archivo bloqueado de modo que SQLite informe 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 

Personalmente lo haría 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(); } } 

Tendrá que escribir un bucle, si esa 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 [].

Esto es lo más compacto que puedo obtener:

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