2011-09-22 13 views
7

Questo è un po 'più complicato di quanto immaginassi. Sto provando a leggere n byte da un flusso.Come faccio a leggere esattamente n byte da uno stream?

Il MSDN claims che Read non deve restituire n byte, deve solo restituire almeno 1 e fino a n byte, con 0 byte essendo il caso speciale di raggiungere la fine del flusso.

In genere, sto usando qualcosa come

var buf = new byte[size]; 
var count = stream.Read (buf, 0, size); 

if (count != size) { 
    buf = buf.Take (count).ToArray(); 
} 

yield return buf; 

Spero in esattamente size byte, ma da spec FileStream sarebbe stato permesso di restituire un gran numero di blocchi 1 byte pure. Questo deve essere evitato.

Un modo per risolverlo sarebbe avere 2 buffer, uno per la lettura e uno per la raccolta dei blocchi finché non si ottiene il numero richiesto di byte. Questo è un po 'ingombrante però.

Ho anche dato uno sguardo a BinaryReader ma la sua specifica inoltre non indica chiaramente che n byte saranno sicuramente restituiti.

Per chiarire: Naturalmente, alla fine del flusso il numero restituito di byte può essere inferiore a size - non è un problema. Sto solo parlando di non ricevere n byte anche se sono disponibili nello stream.

+0

il BinaryReader.ReadBytes (int) '' restituisce il numero di byte richiesti; se il flusso termina prima, restituirà ciò che ha letto fino a quel punto (quindi meno di quanto richiesto). –

+0

@bosonix Sarebbe conveniente. Hai una fonte per queste informazioni? – mafu

+1

questo è specificato nella pagina MSDN https://msdn.microsoft.com/en-us/library/system.io.binaryreader.readbytes(v=vs.110).aspx e ho anche guardato il codice smontato. –

risposta

11

Una versione leggermente più leggibile:

int offset = 0; 
while (offset < count) 
{ 
    int read = stream.Read(buffer, offset, count - offset); 
    if (read == 0) 
     throw new System.IO.EndOfStreamException(); 
    offset += read; 
} 

o scritta come un metodo di estensione per la classe Stream:

public static class StreamUtils 
{ 
    public static byte[] ReadExactly(this System.IO.Stream stream, int count) 
    { 
     byte[] buffer = new byte[count]; 
     int offset = 0; 
     while (offset < count) 
     { 
      int read = stream.Read(buffer, offset, count - offset); 
      if (read == 0) 
       throw new System.IO.EndOfStreamException(); 
      offset += read; 
     } 
     System.Diagnostics.Debug.Assert(offset == count); 
     return buffer; 
    } 
} 
9

Semplicemente; fai un ciclo;

int read, offset = 0; 
while(leftToRead > 0 && (read = stream.Read(buf, offset, leftToRead)) > 0) { 
    leftToRead -= read; 
    offset += read; 
} 
if(leftToRead > 0) throw new EndOfStreamException(); // not enough! 

Dopo questo, buf avrebbe dovuto essere popolato con esattamente la giusta quantità di dati dal flusso, o avrà gettato un EOF.

Problemi correlati