Crear una matriz de bytes de una secuencia

¿Cuál es el método preferido para crear una matriz de bytes a partir de una secuencia de entrada?

Aquí está mi solución actual con .NET 3.5.

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

¿Sigue siendo una mejor idea leer y escribir fragmentos de la secuencia?

Realmente depende de si puedes confiar o no en la s.Length . Para muchas transmisiones, simplemente no sabes cuántos datos habrá. En tales casos, y antes de .NET 4, usaría un 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(); } } 

Con .NET 4 y superior, usaría Stream.CopyTo , que es básicamente equivalente al bucle en mi código: crea MemoryStream , call stream.CopyTo(ms) y luego devuelve ms.ToArray() . Trabajo hecho.

Tal vez debería explicar por qué mi respuesta es más larga que las demás. Stream.Read no garantiza que leerá todo lo que se le pide. Si está leyendo desde un flujo de red, por ejemplo, puede leer el valor de un paquete y luego regresar, incluso si pronto habrá más datos. BinaryReader.Read continuará hasta el final de la transmisión o su tamaño especificado, pero aún debe saber el tamaño para comenzar.

El método anterior seguirá leyendo (y copiando en un MemoryStream) hasta que se quede sin datos. Luego le pide a MemoryStream que devuelva una copia de los datos en una matriz. Si conoces el tamaño para empezar, o crees conocer el tamaño, sin estar seguro, puedes construir el MemoryStream de ese tamaño para empezar. Del mismo modo, puede poner una marca al final, y si la longitud de la secuencia es del mismo tamaño que el búfer (devuelto por MemoryStream.GetBuffer ), entonces simplemente puede devolver el búfer. Por lo tanto, el código anterior no está completamente optimizado, pero al menos será correcto. No asume ninguna responsabilidad por el cierre de la transmisión; la persona que llama debe hacerlo.

Vea este artículo para más información (y una implementación alternativa).

Si bien la respuesta de Jon es correcta, está reescribiendo el código que ya existe en CopyTo. Entonces, para .Net 4 usa la solución de Sandip, pero para la versión anterior de .Net usa la respuesta de Jon. El código de Sandip se mejoraría mediante el uso de “usar”, ya que las excepciones en CopyTo son, en muchas situaciones, bastante probables y dejarían el MemoryStream no eliminado.

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

Solo quiero señalar que, en caso de que tenga un MemoryStream, ya tiene memorystream.ToArray() para eso.

Además, si se trata de flujos de subtipos desconocidos o diferentes y puede recibir un MemoryStream , puede retransmitir dicho método para esos casos y aún así utilizar la respuesta aceptada para los demás, como esta:

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

solo mi pareja de centavos … la práctica que suelo usar es organizar los métodos como este como un ayudante personalizado

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

agregue espacio de nombres al archivo de configuración y úselo en cualquier lugar que desee

Incluso puedes hacerlo más elegante con extensiones:

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

Y luego llámalo como un método regular:

 byte[] arr = someStream.ToByteArray() 

Obtengo un error de tiempo de comstackción con el código de Bob (es decir, el cuestionario). Stream.Length es un largo, mientras que BinaryReader.ReadBytes toma un parámetro entero. En mi caso, no espero estar tratando con Streams lo suficientemente grande como para requerir una gran precisión, así que uso lo siguiente:

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

El de arriba está bien … pero encontrará corrupción de datos cuando envíe cosas a través de SMTP (si es necesario). He cambiado a otra cosa que te ayudará a enviar correctamente byte por 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; }' 

Simplemente puede usar el método ToArray () de la clase MemoryStream, por ejemplo,

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

Puedes usar este método de extensión.

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

Pude hacer que funcione en una sola línea:

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

según lo aclarado por johnnyRose , el código anterior solo funcionará para MemoryStream