流读取问题

6
假设我们有这样一个代码块:
//Assuming s is a stream:
byte[] data = new byte[1000];
s.Read(data,0,data.Length);

read方法可以读取1到1000个字节的数据,但是不会读取完整个流。

这是一本C#书的说法。

我不明白为什么Read方法会从流中任意位置开始读取?它难道不应该读取整个流吗?

书中提到的解决方法如下:

//bytesRead will always end up at 1000, unless the stream is itself smaller in length:
int bytesRead = 0;
int chunkSize = 1;
while(bytesRead < data.Length && chunkSize > 0 )
      bytesRead += chunkSize = s.Read(data,bytesRead,dataLength-bytesRead);

上面的代码也是本书提供的一种解决方案。我想了解的是Read方法是否开始从头读取并将指定范围内的所有字节写入字节数组。为什么他在s.Read(data,bytesRead,dataLength-bytesRead)中使用bytesRead作为起始点呢?

提前感谢。

5个回答

8
这段话讲的是当你调用Read时,数据可能在此刻或以后都不可用。例如,在NetworkStream上,数据可能到达得比你获取得慢。或者你可能接近FileStream的末尾。Stream可能知道剩余的字节数少于你要求的,或者可能无法知道请求的完整字节数何时到达。因此,为了避免等待可能永远不会到达的数据或出现“字节数不足,请再试一次”的错误,Read有权返回少于您所请求的字节数。
因此,当将数据块读入byte数组中时,可能没有填充完整个byte数组。但您希望下一个数据块添加到上一个数据块的结尾,而不是覆盖byte数组的开头。因此需要将bytesRead作为下一个数据块放置在byte数组中的起始位置。

4
“可能读取1到1000字节”这个短语的意思是“可以读取1个字节,2个字节,最多1000个字节”。它指的是读取的字节数量,而不是位置。读取将位于流的当前位置。

2
第一个示例是将字节数组的声明大小1000作为输入参数传递到“Read”方法中。
第二个示例是逐字节读取流,非常适合流入或流出的数据 - 这意味着如果您可以处理接收到的流的部分,而不必先将其全部缓冲到内存中,则这是一种更有效的方法。
我认为您在这里感到困惑的地方是作者人为地将示例限制在最大1,000个字节。许多涉及流式传输的协议通常会在开始时发送一个或两个字节,特别通知使用者整个流的长度,以便最好地对流进行分块和处理,因此不需要声明1,000的限制。获取大小,适当地对其进行分块(包括可能不完整的最后一块),并处理每个块。

你的意思是,它们首先发送要发送的数据大小,然后按块发送整个数据,而不是将其作为一个整体发送? - Tarik
通常是这样的。假设你有一个40MB的磁盘文件要传输。相比于加载整个40MB到内存中再进行传输 - 从而使得40MB的内存在一段时间内变得拥挤 - 你可以只读取,比如前1024字节,然后将其传输,并继续以1024字节块的方式进行。一个文件传输协议可能会规定“第一个数据包的前两个字节包含一个无符号整数,指示有效负载的大小”,这样你就知道何时停止读取来自该流的数据了。接收端也可以采用同样的方式 - 将它分成1024字节或其他资源友好的缓冲区数量。 - cfeduke

1
我不明白为什么Read方法会从流的任何位置读取?它不是要读取整个流吗?
Read允许您指定读取的起点和终点。有关更多信息,请参见itowlson的答案。
我试图理解的是,Read方法是否开始读取到末尾并将指定范围内的所有字节写入字节数组。
如果这是一个问题,我想答案是否定的。Read方法会在指定的起点和终点从流中填充数据到数组中。
他为什么要在s.Read(data,bytesRead,dataLength-bytesRead)中使用bytesRead作为起始点?
他使用bytesRead来跟踪“读取的字节数量”。这使他知道在下一次Read调用中从哪里开始阅读。

0
根据我对Read方法文档的阅读,由于流可以用于读取各种数据源,从键盘输入到文件再到网络流量,因此具体实现是否返回read方法请求的字节数是开放的。例如,如果用于读取网络数据的特定实现想要返回已经可用的500字节数据以响应Web请求,但它预计在读取1000字节之前不会完成,并且您请求了1000字节,则它可能会返回它所拥有的数据以便您进行处理。它会告诉您它只读取了500字节,并且您应该意识到可能还有更多的数据正在路上。1000字节的最大值只是一个指示,表示您不希望一次处理超过1000字节。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接