如果我读取的字节尚未出现,BinaryReader会做什么?

11

我正在使用BinaryReader来读取网络数据,其基于NetworkStream。这对我非常有效,但我想了解底层的工作原理,所以我查看了BinaryReader的文档,并发现它非常简略。

我的问题是:当我调用ReadBytes时,如果网络流中不存在bufferSize字节,BinaryReader.ReadBytes(bufferSize)会发生什么?

在我看来,有几个选项:
1) 读取网络流中存在的任何字节,并返回此数量
2) 等待直到网络流中存在bufferSize字节,然后再读取
3) 抛出异常

我假设选项2会发生,因为我从未收到过任何异常,并且我接收到的所有数据都是完整的,而不是分段的。但是,我想确定到底发生了什么。如果有人能帮助我澄清疑问,我将不胜感激。


2
它将阻塞并确保您获得所需的字节数。只有在流被关闭并且您已经读取了所有字节时,您才会获得更少的字节。 - Hans Passant
2个回答

13

我认为它实际上适用于隐藏选项4:

  • 读取数据时,随着数据变得可用,循环方式与您通常手动执行的方式相同。只有在读取时达到流的末尾时,它才会返回小于您请求的字节数的值。

这与您的选项2略有不同,因为它会随着数据变得可用而从流中读取数据 - 它不会等到一次性读取所有数据。

如果达到结尾,很容易证明它确实会返回比您请求的字节数更少的字节数:

var ms = new MemoryStream(new byte[10]);
var readData = new BinaryReader(ms).ReadBytes(100);
Console.WriteLine(readData.Length); // 10

如果没有自定义流,要证明循环部分会更加困难,因为这需要多次 Read 调用才能返回所有数据。

文档并不是非常清晰,但是返回值部分至少有点帮助:

一个包含从基础流中读取的数据的字节数组。如果已到达流的结尾,可能会少于请求的字节数。

请注意我强调的最后一部分,并将其与 Stream.Read 进行比较:

读入缓冲区的总字节数。如果当前没有那么多可用的字节,则该数量可能小于所请求的字节数,如果已到达流的结尾,则为零 (0)。

如果您期望精确量的数据,并且只有该数据量才有用,我建议您编写一个 ReadExactly 方法,该方法调用 Read 并在流关闭之前提供的数据不足时抛出 EndOfStreamException


谢谢您详细的回复。不过我只有一个快速、简单的问题。只有在流关闭的情况下才能到达流的末尾,对吗? - Darkhydro

0

如果你问“在流上是否存在”,是指该方法会阻塞直至指定数量的字节可用,那么答案是选项2。只有当到达流末尾时,它才会返回少量字节。

这里是一个演示如何实现BinaryReader.ReadBytes(int)的示例代码:

byte[] ReadBytes(int count)
{
    byte[] buffer = new byte[count];
    int total = 0;
    int read = 0;

    do
    {
        read = stream.Read(buffer, read, count - total);
        total += read;
    }
    while (read > 0 && total < count);

    // Resize buffer if smaller than count (code not shown).

    return buffer;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接