2011-09-22 50 views
7

这比我第一次想象的要复杂一些。我试图从流中读取n个字节。如何从流中精确读取n个字节?

MSDN claims Read不必返回n个字节,它只需返回至少1到最多n个字节,其中0个字节是到达流结束的特殊情况。

通常情况下,我使用的是类似

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

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

yield return buf; 

我希望的正是size字节,但通过规范的FileStream将被允许返回大量的1字节块为好。这必须避免。

解决此问题的一种方法是拥有2个缓冲区,一个用于读取,另一个用于收集块,直到获得请求的字节数。虽然这有点麻烦。

我也看了一下BinaryReader,但是它的规范也没有明确说明n个字节肯定会返回。

澄清:当然,在流结束时,返回的字节数可能会少于size - 这不是问题。即使它们在流中可用,我也只谈论没有收到n个字节。

+0

的'BinaryReader.ReadBytes(INT)'返回请求的字节数;如果流更早结束,它将返回所读取的内容直到该点(如此少于要求)。 –

+0

@bosonix这会很方便。你有这个信息的来源吗? – mafu

+1

这是在MSDN页面https://msdn.microsoft.com/en-us/library/system.io.binaryreader.readbytes(v=vs.110).aspx中指定的,我也查看了反汇编代码。 –

回答

11

稍微更可读的版本:

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

或写入作为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

简单地说;你循环;

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! 

在此之后,buf应已填入从数据流的完全正确的金额,或将抛出一个EOF。

相关问题