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