FileStream.Read()
返回读取的字节数,但是...除了到达文件末尾之外还有其它情况,它会读取的字节数少于请求的字节数而不是例外?
文件说:
Read方法仅在到达流的末尾后才返回零。否则,Read总是在返回之前从流中读取至少一个字节。如果在调用Read时流中没有可用数据,则该方法将阻塞,直到可以返回至少一个字节的数据。即使尚未到达流的末尾,实现也可以自由返回少于请求的字节数。
但是这并没有解释数据在什么情况下不可用并导致方法阻塞直到它可以再次读取。我的意思是,在数据不可用的大多数情况下是否应该强制例外?
将读取的字节数与预期字节数进行比较的实际情况可能有所不同(假设我们在提到预期的字节数时已经检查了文件结尾)?
编辑:更多信息,我之所以这样问是因为我遇到了一些代码,开发人员几乎做了类似这样的事情:< / p>
bytesExpected = (remainingBytesInFile > 94208 ? 94208 : remainingBytesInFile
while (bytesRead < bytesExpected)
{
bytesRead += fileStream.Read(buffer, bytesRead, bytesExpected - bytesRead)
}
现在,我完全没有看到任何优势,如果它无法读取预期的字节数,我会期望它会抛出异常(请记住它&bearing #39; s已经考虑到还有很多字节需要阅读)
对于这样的事情,人们可能会有什么原因?我确定我错过了什么
答案 0 :(得分:3)
该文档适用于Stream.Read
,FileStream
来自FileStream
。由于NetworkStream
是一个流,因此它应该遵守流合同。并非所有流都可以,但除非你有充分的理由,否则你应该坚持这一点。
在典型的文件流中,当到达文件末尾时,您将只获得小于count的返回值(这是检查文件末尾的一种非常简单的方法)。
但是,例如,在Read
中,您将继续读取循环,直到该方法返回零为止 - 表示流的结束。同样适用于文件流 - 当FileStream
返回零时,您知道文件末尾。
最重要的是,PRN
不仅适用于您考虑的文件 - 例如,它也适用于标准输入/输出管道和COM端口等伪文件(尝试在{{上打开文件流) 1}},例如)。在这种情况下,您不会读取具有固定长度的文件,其行为与NetworkStream
相同。
最后,不要忘记FileStream
没有密封。例如,实现虚拟化文件系统非常好 - 如果您的虚拟化文件系统不支持搜索或检查文件长度,那就完全没问题了。
修改强>
要解决您的编辑问题,这正是您应该阅读任何流的方式。它没有错。如果在流中没有其他内容可读,Read
方法将只返回0
,并且您知道流已结束。唯一的问题是,似乎他试图将缓冲区一次填充到一个缓冲区 - 这只有在你明确需要将文件分区94208字节并传递byte[]
进行进一步处理时才有意义某处。
如果情况并非如此,那么你真的不需要填充完整的缓冲区 - 你只需继续阅读(并且可能在其他方面写作),直到Read
返回0
。事实上,默认情况下,FileStream
将始终填充整个缓冲区,除非它是围绕管道句柄构建的 - 但由于这是可能的,您不应该依赖于“真实文件”行为,所以只要你需要那些byte[]
非流(例如解析消息),这就完全没问题了。如果您只是将流用作实际流,并且您正在将数据流式传输到其他地方,那么它确实没有意义 - 您只需要一个while
来读取该文件。
答案 1 :(得分:0)
您的期望仅适用于流从无延迟源读取数据的情况。其他I / O源可能很慢,这就是Read
方法可能无法始终立即返回的原因。这并不意味着存在错误(因此没有异常),只是它必须等待数据到达。
示例:网络流,慢速磁盘上的文件流等
(UPDATE,HDD示例)提供特定于文件的示例(因为您的案例为FileStream
,但Read
上定义了Stream
,因此所有的实现都应该满足要求):机械硬盘进入&#34;睡眠&#34;当不活动时(特别是在电池供电的设备上,阅读笔记本电脑)。旋转可能需要一秒钟左右。这不是IOException
,但在读取任何数据之前,您的读取必须等待一秒钟。
答案 2 :(得分:0)
简单的回答是,在FileStream上它可能永远不会发生。 但请记住,Read方法是从Stream继承的,它作为NetworkStream等许多其他流的基础,在这种情况下,您可能无法读取具有许多字节的要求,因为它们尚未从网络接收。
所以文档说这一切都取决于特定类型的流的实现 - FileStream,NetworkStream等。