Criando uma matriz de bytes de um stream

Qual é o método preferido para criar uma matriz de bytes de um stream de input?

Aqui está a minha solução atual com o .NET 3.5.

Stream s; byte[] b; using (BinaryReader br = new BinaryReader(s)) { b = br.ReadBytes((int)s.Length); } 

Ainda é melhor ler e escrever trechos do stream?

Isso realmente depende se você pode ou não confiar em s.Length . Para muitos streams, você simplesmente não sabe quantos dados haverá. Em tais casos – e antes do .NET 4 – eu usaria código como este:

 public static byte[] ReadFully(Stream input) { byte[] buffer = new byte[16*1024]; using (MemoryStream ms = new MemoryStream()) { int read; while ((read = input.Read(buffer, 0, buffer.Length)) > 0) { ms.Write(buffer, 0, read); } return ms.ToArray(); } } 

Com o .NET 4 e acima, eu usaria Stream.CopyTo , que é basicamente equivalente ao loop no meu código – crie o MemoryStream , chame stream.CopyTo(ms) e, em seguida, retorne ms.ToArray() . Tarefa concluída.

Talvez eu deva explicar por que minha resposta é mais longa que as outras. Stream.Read não garante que lerá tudo o que for solicitado. Se você estiver lendo de um stream de rede, por exemplo, ele pode ler o valor de um pacote e depois retornar, mesmo que haja mais dados em breve. BinaryReader.Read continuará até o final do stream ou seu tamanho especificado, mas você ainda precisa saber o tamanho para começar.

O método acima continuará lendo (e copiando em um MemoryStream) até ficar sem dados. Em seguida, ele pede ao MemoryStream para retornar uma cópia dos dados em uma matriz. Se você sabe o tamanho para começar – ou acha que sabe o tamanho, sem ter certeza – você pode construir o MemoryStream para ser esse tamanho para começar. Da mesma forma você pode colocar uma verificação no final, e se o comprimento do stream é o mesmo tamanho que o buffer (retornado por MemoryStream.GetBuffer ), então você pode simplesmente retornar o buffer. Portanto, o código acima não é otimizado, mas pelo menos estará correto. Não assume qualquer responsabilidade pelo fechamento do stream – o chamador deve fazer isso.

Veja este artigo para mais informações (e uma implementação alternativa).

Enquanto a resposta de Jon está correta, ele está reescrevendo o código que já existe no CopyTo. Então, para .Net 4 use a solução da Sandip, mas para a versão anterior do .Net use a resposta de Jon. O código do Sandip seria melhorado pelo uso de “using”, já que exceções no CopyTo são, em muitas situações, bastante prováveis ​​e deixariam o MemoryStream não descartado.

 public static byte[] ReadFully(Stream input) { using (MemoryStream ms = new MemoryStream()) { input.CopyTo(ms); return ms.ToArray(); } } 

Só quero salientar que no caso de você ter um MemoryStream você já tem memorystream.ToArray() para isso.

Além disso, se você estiver lidando com streams de subtipos desconhecidos ou diferentes e puder receber um MemoryStream , será possível retransmitir o método para esses casos e ainda usar a resposta aceita para os outros, assim:

 public static byte[] StreamToByteArray(Stream stream) { if (stream is MemoryStream) { return ((MemoryStream)stream).ToArray(); } else { // Jon Skeet's accepted answer return ReadFully(stream); } } 
 MemoryStream ms = new MemoryStream(); file.PostedFile.InputStream.CopyTo(ms); var byts = ms.ToArray(); ms.Dispose(); 

apenas o meu par centavos … a prática que eu uso frequentemente é organizar os methods como este como um ajudante personalizado

 public static class StreamHelpers { public static byte[] ReadFully(this Stream input) { using (MemoryStream ms = new MemoryStream()) { input.CopyTo(ms); return ms.ToArray(); } } } 

adicione namespace ao arquivo de configuração e use-o em qualquer lugar que você desejar

Você pode até torná-lo mais extravagante com extensões:

 namespace Foo { public static class Extensions { public static byte[] ToByteArray(this Stream stream) { using (stream) { using (MemoryStream memStream = new MemoryStream()) { stream.CopyTo(memStream); return memStream.ToArray(); } } } } } 

E então chame isso como um método regular:

 byte[] arr = someStream.ToByteArray() 

Eu recebo um erro de compilation com o código de Bob (ou seja, o do questionador). Stream.Length é longo, enquanto que BinaryReader.ReadBytes usa um parâmetro inteiro. No meu caso, não espero estar lidando com Streams grandes o suficiente para exigir precisão longa, portanto, uso o seguinte:

 Stream s; byte[] b; if (s.Length > int.MaxValue) { throw new Exception("This stream is larger than the conversion algorithm can currently handle."); } using (var br = new BinaryReader(s)) { b = br.ReadBytes((int)s.Length); } 

O acima é ok … mas você encontrará dados corrompidos quando você enviar coisas através de SMTP (se você precisar). Eu alterei para outra coisa que ajudará a enviar corretamente byte para byte: ‘

 using System; using System.IO; private static byte[] ReadFully(string input) { FileStream sourceFile = new FileStream(input, FileMode.Open); //Open streamer BinaryReader binReader = new BinaryReader(sourceFile); byte[] output = new byte[sourceFile.Length]; //create byte array of size file for (long i = 0; i < sourceFile.Length; i++) output[i] = binReader.ReadByte(); //read until done sourceFile.Close(); //dispose streamer binReader.Close(); //dispose reader return output; }' 

Você pode simplesmente usar o método ToArray () da class MemoryStream, por

 MemoryStream ms = (MemoryStream)dataInStream; byte[] imageBytes = ms.ToArray(); 

Você pode usar este método de extensão.

 public static class StreamExtensions { public static byte[] ToByteArray(this Stream stream) { var bytes = new List(); int b; while ((b = stream.ReadByte()) != -1) bytes.Add((byte)b); return bytes.ToArray(); } } 
 public static byte[] ToByteArray(Stream stream) { if (stream is MemoryStream) { return ((MemoryStream)stream).ToArray(); } else { byte[] buffer = new byte[16 * 1024]; using (MemoryStream ms = new MemoryStream()) { int read; while ((read = stream.Read(buffer, 0, buffer.Length)) > 0) { ms.Write(buffer, 0, read); } return ms.ToArray(); } } } 

Consegui fazer isso funcionar em uma única linha:

 byte [] byteArr= ((MemoryStream)localStream).ToArray(); 

como esclarecido por johnnyRose , o código acima funcionará apenas para o MemoryStream