文档说:
返回值:
读取到缓冲区的总字节数。如果当前没有那么多字节可用,则这可以小于请求的字节数,或者如果已经到达流的末尾,则可以为零(0)。
但是,为什么从磁盘读取时字节"不可用"呢?
让我澄清一下:
- 我正在从磁盘读取(底层类型为
FileStream
) - 至少还有个
N
字节需要读取(在EOF
之前) - 我请求读取
N
字节
在这种情况下,返回值/读取的字节数是否会小于N
?
回答您编辑的问题:
在这种情况下,返回值/读取的字节数是否会小于N?
我想你需要问一位硬件专家,我想这不是吸引这样一个人注意的合适论坛。
免责声明:我不是硬件专家,也不在电视上玩。这只是猜测:
我认为当你从磁盘读取时,你得到的字节比你请求的少的唯一原因是因为流已经没有字节了。然而,可以想象,您可能会遇到类似于网络流的情况,即您的程序读取字节的速度比硬件提供字节的速度快。在这种情况下,Read方法可能只填充部分缓冲区,然后返回。
显然,这个问题的答案取决于这种情况是否会发生。我认为答案是"不"。我当然从来没有见过反例。但是,根据这种假设编写代码是错误的。
考虑一下:即使你可以模拟代码运行的所有硬件的规格,并证明缓冲区总是会被完全填满,直到流结束,也不知道将来有人可能在机器上安装什么新的磁盘驱动器,这可能会有不同的表现。只需对所有流进行相同的处理,并承担处理缓冲区未完全填充的可能性所需的少量工作,就简单得多。
我的解决方案:
public static class StreamExt
{
public static void ReadBytes(this Stream stream, byte[] buffer, int offset, int count)
{
int totalBytesRead = 0;
while (totalBytesRead < count)
{
int bytesRead = stream.Read(buffer, offset + totalBytesRead, count - totalBytesRead);
if (bytesRead == 0) throw new IOException("Premature end of stream");
totalBytesRead += bytesRead;
}
}
}
使用此方法应该可以安全地读取您请求的所有字节。
至于潜在原因(另见Lloyd提供的)
- 上次读取时达到EOF
- 网络流中还没有数据
- 自定义stram决定以固定大小的块返回数据(完全可以)
Stream.Read
要求您预先分配要读取的空间,如果您分配了更多的空间,那么就可以从流中读取,那么返回值就是它告诉您已经使用了多少空间的方式。
考虑以下内容:
如果您分配了一个4096字节的缓冲区,并且在2046达到EOF
,那么返回值将仅为2046。这可以让您知道返回时缓冲区已满的量。