Gravar arquivo do stream de resources de assembly em disco

Não consigo encontrar uma maneira mais eficiente de “copiar” um recurso incorporado para o disco do que o seguinte:

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 não haver maneira mais direta de fazer a cópia, a menos que eu esteja perdendo alguma coisa …

Não sei por que você está usando o BinaryReader / BinaryWriter . Pessoalmente, eu começaria com um método utilitário ú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); } } 

então chame:

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

Você pode alterar o tamanho do buffer, claro, ou tê-lo como um parâmetro para o método – mas o ponto principal é que este é um código mais simples . É mais eficiente? Não. Tem certeza de que você realmente precisa desse código para ser mais eficiente? Você realmente tem centenas de megabytes que você precisa gravar no disco?

Eu acho que raramente preciso de código para ser ultra-eficiente, mas quase sempre preciso que seja simples. O tipo de diferença de desempenho que você pode ver entre esta e uma abordagem “inteligente” (se estiver disponível) não é provável que seja um efeito de mudança de complexidade (por exemplo, O (n) para O (log n)) – e esse é o tipo de ganho de desempenho que realmente pode valer a pena perseguir.

EDIT: Como observado nos comentários, o .NET 4.0 tem Stream.CopyTo para que você não precise codificar isso sozinho.

Se o recurso (arquivo) for binário.

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

E se o recurso (arquivo) for texto.

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

Na verdade, acabei usando esta linha única: Assembly.GetExecutingAssembly().GetManifestResourceStream("[Project].[File]").CopyTo(New FileStream(FileLocation, FileMode.Create)) . Claro, isso é para .net 4.0

Atualização: Descobri que a linha acima pode manter um arquivo bloqueado de forma que o SQLite relate que o database é somente leitura. Por isso acabei com o seguinte:

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

Pessoalmente eu faria assim:

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

Você terá que escrever um loop, se essa é a sua pergunta. Mas você poderia fazer sem o leitor e o escritor, já que o Stream básico já lida com dados de byte [].

Isso é o mais compacto possível:

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