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有什么好处,如果它不能读取预期的字节数,我希望它抛出一个异常(记住它已经考虑了还有很多字节要读)

为什么会有这样的事情呢?我确信我错过了一些

FileStream.Read() -读取字节数

文档是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等