2009-06-04 8 views
9

Fino ad ora sto contando 12 LoC. Potresti renderlo più piccolo?Come copiare un flusso in un array di byte con il codice C# più piccolo?

using (Stream fileStream = File.OpenRead(fileName)) 
{ 
    using (BinaryReader binaryReader = new BinaryReader(fileStream)) 
    { 
     using (MemoryStream memoryStream = new MemoryStream()) 
     { 
      byte[] buffer = new byte[256]; 
      int count; 
      int totalBytes = 0; 
      while ((count = binaryReader.Read(buffer, 0, 256)) > 0) 
      { 
       memoryStream.Write(buffer, 0, count); 
       totalBytes += count; 
      } 
      memoryStream.Position = 0; 
      byte[] transparentPng = new byte[totalBytes]; 
      memoryStream.Read(transparentPng, 0, totalBytes); 
     } 
    } 
} 

risposta

30

C'è un metodo statico che può fare questo per voi in una sola chiamata.

var data = File.ReadAllBytes(fileName); 

alternativa, un metodo che funziona per qualsiasi Stream (che restituisce la sua lunghezza) sarebbe:

byte[] data; 
using (var br = new BinaryReader(stream)) 
    data = br.ReadBytes((int)stream.Length); 

Per gli stream che non hanno una lunghezza ben definita (es NetworkStream), e quindi sollevare un'eccezione chiamando il stream.Length, questo naturalmente non funziona. La soluzione leggermente più complicata presentata nella risposta di Jon Skeet è quindi ciò che probabilmente vorrai.

+5

Non tutti gli stream restituiscono la loro lunghezza sebbene ... –

+0

data = binaryReader.ReadBytes (stream.Length); dovrebbe essere data = br.ReadBytes (stream.Length); – OneSHOT

+0

Sì, evviva. Errore di battitura evidente. – Noldorin

27

Come 'bout uno:

byte[] result = File.ReadAllBytes(fileName); 
+0

+1 Ben fatto :) –

+2

Anche se funziona solo per i file, naturalmente ... che corrisponda al codice nella domanda originale, ma non il titolo della domanda :) –

+0

Buon punto.Forse se mi annoierò più tardi esprimerò questo in termini di una funzione che accetta un flusso aperto come input - per tutti i frammenti di codice nessuno si è preoccupato di mettere ancora una firma di funzione. –

8

Anche se non riducendo la LOC (non avevo mai usare questo come motivazione primaria), è possibile comprimere i usings come questo:

using (Stream fileStream = File.OpenRead(fileName)) 
using (BinaryReader binaryReader = new BinaryReader(fileStream)) 
using (MemoryStream memoryStream = new MemoryStream()) 
{ 
    byte[] buffer = new byte[256]; 
    int count; 
    int totalBytes = 0; 
    while ((count = binaryReader.Read(buffer, 0, 256)) > 0) 
    { 
     memoryStream.Write(buffer, 0, count); 
     totalBytes += count; 
    } 
    memoryStream.Position = 0; 
    byte[] transparentPng = new byte[totalBytes]; 
    memoryStream.Read(transparentPng, 0, totalBytes);  
} 
+0

Bel trucco, grazie. –

+0

Bel trucco con le diverse istruzioni using –

+3

"perché importa se funziona?" Non importa finché non devi mantenere il codice ;-) – fretje

15

Ridurre le linee di codice è piuttosto semplice qui (mentre si lavora con i flussi arbitrarie, piuttosto che file):

using (Stream fileStream = File.OpenRead(fileName)) 
using (MemoryStream memoryStream = new MemoryStream()) 
{ 
    int byteRead; 
    while ((byteRead = fileStream.ReadByte()) != -1) 
    { 
     memoryStream.WriteByte(byteRead); 
    } 
    return memoryStream.ToArray(); 
} 

Ovviamente è molto più efficiente per leggere in un buffer che per leggere un byte alla volta, ma questo riduce il numero di dichiarazioni (come si don Devo dichiarare sia un buffer e una variabile per contenere il valore di ritorno da Stream). Chiamare MemoryStream.ToArray() è più semplice della lettura in un array di nuova costruzione.

L'utilizzo di un buffer è tuttavia più piacevole. Si noti che abbiamo davvero non abbiamo bisogno BinaryReader:

using (Stream fileStream = File.OpenRead(fileName)) 
using (MemoryStream memoryStream = new MemoryStream()) 
{ 
    byte[] buffer = new byte[8192]; 
    int bytesRead; 
    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) > 0) 
    { 
     memoryStream.Write(buffer, 0, bytesRead); 
    } 
    return memoryStream.ToArray(); 
} 

Se vuoi essere davvero brutale, potremmo ridurre il numero di using dichiarazioni (con entrambe le soluzioni):

using (Stream fileStream = File.OpenRead(fileName), 
       memoryStream = new MemoryStream()) 
{ 
    byte[] buffer = new byte[8192]; 
    int bytesRead; 
    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) > 0) 
    { 
     memoryStream.Write(buffer, 0, bytesRead); 
    } 
    return ((MemoryStream)memoryStream).ToArray(); 
} 

ma questo è semplicemente brutto :)

Un'altra opzione, naturalmente, è utilizzare una libreria come MiscUtil che ha un metodo per leggere completamente da un flusso :) Il metodo di utilità può essere semplice come questo:

public static byte[] ReadFully(this Stream stream) 
{ 
    using (MemoryStream memoryStream = new MemoryStream()) 
    { 
     byte[] buffer = new byte[8192]; 
     int bytesRead; 
     while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) 
     { 
      memoryStream.Write(buffer, 0, bytesRead); 
     } 
     return memoryStream.ToArray(); 
    } 
} 

Si noti che questo mai chiude il flusso - il chiamante deve farlo.

2

Basta utilizzare il metodo del StreamCopyTo per copiare ad un MemoryStream, e ottenere la matrice:

using (var fileStream = File.OpenRead(fileName)) 
{ 
    using (var memoryStream = new MemoryStream()) 
    { 
     fileStream.CopyTo(memoryStream); 
     memoryStream.Seek(0, SeekOrigin.Begin); 

     byte[] transparentPng = memoryStream.ToArray(); 
    } 
}