FileStream.Read() - 读取的字节数
FileStream.Read() - bytes read
FileStream.Read()
returns 读取的字节数,但是...除了已到达文件末尾之外,是否还有其他情况会导致读取的字节数少于请求的字节数并且不抛出异常?
文档说:
The Read method returns zero only after reaching the end of the stream. Otherwise, Read always reads at least one byte from the stream before returning. If no data is available from the stream upon a call to Read, the method will block until at least one byte of data can be returned. An implementation is free to return fewer bytes than requested even if the end of the stream has not been reached.
但这并不能完全解释在什么情况下数据不可用并导致方法阻塞,直到它可以再次读取。我的意思是,大多数数据不可用的情况不应该强制异常吗?
在哪些实际情况下,将读取的字节数与预期字节数进行比较可能会有所不同(假设我们在提到预期字节数时已经在检查文件结尾)?
编辑: 更多信息,我问这个的原因是因为我遇到了一些代码,开发人员几乎做了这样的事情:
bytesExpected = (remainingBytesInFile > 94208 ? 94208 : remainingBytesInFile
while (bytesRead < bytesExpected)
{
bytesRead += fileStream.Read(buffer, bytesRead, bytesExpected - bytesRead)
}
现在,我完全看不出这样做有什么好处,如果它无法读取预期的字节数,我希望它会抛出异常(记住它已经考虑到了还有那么多字节要读)
这样的事情可能有什么原因?我确定我遗漏了什么
您的期望仅适用于流从无延迟源读取数据的情况。其他 I/O 源可能很慢,这就是为什么 Read
方法可能并不总是能够立即 return 的原因。这并不意味着有错误(所以没有例外),只是它必须等待数据到达。
示例:网络流、慢盘上的文件流等
(更新,HDD 示例) 举一个特定于文件的示例(因为您的情况是 FileStream
,尽管 Read
定义在 Stream
所以所有的实现都应该满足要求):机械硬盘驱动器在不活动时进入 "sleep"(特别是在电池供电的设备上,阅读笔记本电脑)。旋转可能需要一秒钟左右。那不是 IOException
,但您的读取必须等待一秒钟才能读取任何数据。
简单的答案是,在 FileStream 上它可能永远不会发生。
但是请记住,Read 方法是从 Stream 继承的,它作为许多其他流(如 NetworkStream)的基础,在这种情况下,您可能无法读取您请求的许多字节,因为它们还没有从网络接收到。
所以就像文档说的那样,这完全取决于特定流类型的实现 - FileStream、NetworkStream 等
文档是针对 Stream.Read
的,FileStream
是从中派生出来的。由于 FileStream
是一个流,它应该遵守流契约。并非所有流都这样做,但除非你有充分的理由,否则你应该坚持这一点。
在典型的文件流中,当您到达文件末尾时,您只会得到一个小于 count 的 return 值(这是一种非常简单的检查文件末尾的方法)。
但是,例如,在 NetworkStream
中,您会一直循环读取,直到方法 return 为零 - 表示流结束。这同样适用于文件流 - 当 Read
return 为零时,你知道你在文件的末尾。
最重要的是,FileStream
不仅适用于您认为的文件 - 它也适用于伪文件,例如标准 input/output 管道和 COM 端口(尝试打开一个文件例如 PRN
上的流)。在这种情况下,您不是在读取固定长度的文件,其行为与 NetworkStream
.
相同
最后,不要忘记 FileStream
没有被密封。例如,实现虚拟化文件系统对您来说完全没问题 - 如果您的虚拟化文件系统不支持查找或检查文件长度,那也完全没问题。
编辑:
为了解决您的编辑问题,这正是您应该如何阅读任何流。没有错。如果流中没有其他内容可读,Read
方法将简单地 return 0
,并且您知道流已结束。唯一的问题是,他似乎试图将缓冲区填满,一次填满一个缓冲区——这只有在您明确需要按 94208 字节对文件进行分区并传递 byte[]
进行进一步处理时才有意义某处。
如果不是这种情况,您实际上不需要填满整个缓冲区 - 您只需继续阅读(并可能在另一边写)直到 Read
returns 0
。事实上,默认情况下,FileStream
将始终填满整个缓冲区 ,除非 它是围绕管道句柄构建的 - 但既然有可能,你不应该依赖 "real file" 行为,所以只要你需要那些 byte[]
来处理非流的东西(例如解析消息),这就完全没问题。如果您仅将流用作实际流,并且将数据流式传输到其他地方,那么它没有意义,真的 - 您只需要一个 while
来读取文件。
FileStream.Read()
returns 读取的字节数,但是...除了已到达文件末尾之外,是否还有其他情况会导致读取的字节数少于请求的字节数并且不抛出异常?
文档说:
The Read method returns zero only after reaching the end of the stream. Otherwise, Read always reads at least one byte from the stream before returning. If no data is available from the stream upon a call to Read, the method will block until at least one byte of data can be returned. An implementation is free to return fewer bytes than requested even if the end of the stream has not been reached.
但这并不能完全解释在什么情况下数据不可用并导致方法阻塞,直到它可以再次读取。我的意思是,大多数数据不可用的情况不应该强制异常吗?
在哪些实际情况下,将读取的字节数与预期字节数进行比较可能会有所不同(假设我们在提到预期字节数时已经在检查文件结尾)?
编辑: 更多信息,我问这个的原因是因为我遇到了一些代码,开发人员几乎做了这样的事情:
bytesExpected = (remainingBytesInFile > 94208 ? 94208 : remainingBytesInFile
while (bytesRead < bytesExpected)
{
bytesRead += fileStream.Read(buffer, bytesRead, bytesExpected - bytesRead)
}
现在,我完全看不出这样做有什么好处,如果它无法读取预期的字节数,我希望它会抛出异常(记住它已经考虑到了还有那么多字节要读)
这样的事情可能有什么原因?我确定我遗漏了什么
您的期望仅适用于流从无延迟源读取数据的情况。其他 I/O 源可能很慢,这就是为什么 Read
方法可能并不总是能够立即 return 的原因。这并不意味着有错误(所以没有例外),只是它必须等待数据到达。
示例:网络流、慢盘上的文件流等
(更新,HDD 示例) 举一个特定于文件的示例(因为您的情况是 FileStream
,尽管 Read
定义在 Stream
所以所有的实现都应该满足要求):机械硬盘驱动器在不活动时进入 "sleep"(特别是在电池供电的设备上,阅读笔记本电脑)。旋转可能需要一秒钟左右。那不是 IOException
,但您的读取必须等待一秒钟才能读取任何数据。
简单的答案是,在 FileStream 上它可能永远不会发生。 但是请记住,Read 方法是从 Stream 继承的,它作为许多其他流(如 NetworkStream)的基础,在这种情况下,您可能无法读取您请求的许多字节,因为它们还没有从网络接收到。
所以就像文档说的那样,这完全取决于特定流类型的实现 - FileStream、NetworkStream 等
文档是针对 Stream.Read
的,FileStream
是从中派生出来的。由于 FileStream
是一个流,它应该遵守流契约。并非所有流都这样做,但除非你有充分的理由,否则你应该坚持这一点。
在典型的文件流中,当您到达文件末尾时,您只会得到一个小于 count 的 return 值(这是一种非常简单的检查文件末尾的方法)。
但是,例如,在 NetworkStream
中,您会一直循环读取,直到方法 return 为零 - 表示流结束。这同样适用于文件流 - 当 Read
return 为零时,你知道你在文件的末尾。
最重要的是,FileStream
不仅适用于您认为的文件 - 它也适用于伪文件,例如标准 input/output 管道和 COM 端口(尝试打开一个文件例如 PRN
上的流)。在这种情况下,您不是在读取固定长度的文件,其行为与 NetworkStream
.
最后,不要忘记 FileStream
没有被密封。例如,实现虚拟化文件系统对您来说完全没问题 - 如果您的虚拟化文件系统不支持查找或检查文件长度,那也完全没问题。
编辑:
为了解决您的编辑问题,这正是您应该如何阅读任何流。没有错。如果流中没有其他内容可读,Read
方法将简单地 return 0
,并且您知道流已结束。唯一的问题是,他似乎试图将缓冲区填满,一次填满一个缓冲区——这只有在您明确需要按 94208 字节对文件进行分区并传递 byte[]
进行进一步处理时才有意义某处。
如果不是这种情况,您实际上不需要填满整个缓冲区 - 您只需继续阅读(并可能在另一边写)直到 Read
returns 0
。事实上,默认情况下,FileStream
将始终填满整个缓冲区 ,除非 它是围绕管道句柄构建的 - 但既然有可能,你不应该依赖 "real file" 行为,所以只要你需要那些 byte[]
来处理非流的东西(例如解析消息),这就完全没问题。如果您仅将流用作实际流,并且将数据流式传输到其他地方,那么它没有意义,真的 - 您只需要一个 while
来读取文件。