我想知道一种情况 Read(char[],int,int) 未能返回所有请求的字符,而 ReadBlock() 按预期返回所有字符(比如当 StreamReader 与 FileStream 对象的实例一起工作时)。
2 回答
在实践中,当使用 aStreamReader
时,它只可能发生在可能延迟一段时间的流上——例如人们在这里提到的网络流。
但是,通常情况下,您可以期望它在任何时候发生(包括可能与 .NET 的未来版本在当前没有发生的情况下 -在没有记录TextReader
的情况下它不会发生,所以不能保证将来不会发生)。StreamReader
FileStream
特别是在很多情况下,如果实施者可以通过清空当前缓冲区来部分完成调用,则更容易(具有更简单、更可靠和可能更有效的代码的连锁效应)不返回请求的数量,或者TextReader
在执行只能返回较少字符数的操作之前,使用请求的数量作为传递给支持源(流或另一个)的数量。
现在,回答“何时使用 StreamReader.ReadBlock()?”的实际问题。(或更一般地说,何时使用 TextReader.ReadBlock())。应牢记以下几点:
两者
Read()
和ReadBlock()
都保证至少返回一个字符,除非已读取整个源。如果有待处理的内容,两者都不会返回 0。调用
ReadBlock()
whenRead()
will do 是一种浪费,因为它不必要地循环。但另一方面,它并没有那么浪费。
但另一方面,
Read()
返回少于请求字符的情况通常是另一个线程正在获取将填充缓冲区以进行下一次调用的内容的情况,或者该内容尚不存在的情况(例如用户输入或另一台机器上的待处理操作) - 在处理部分结果并Read()
在完成后再次调用时可以找到更好的整体并发性。
所以。如果你可以用部分结果做一些有用的事情,那么打电话Read()
并处理你得到的东西。特别是如果您正在循环并处理每个结果,Read()
那么请执行此操作而不是使用ReadBlock()
.
一个值得注意的情况是,如果您正在构建自己的 TextReader 并由另一个支持。除非算法确实需要一定数量的字符才能工作,否则调用是没有意义ReadBlock()
的——只要从调用中返回尽可能多的内容,Read()
并在需要时让调用代码调用ReadBlock()
。
特别要注意以下代码:
char buffer = char[4096];
int len = 0;
while((len = tr.ReadBlock(buffer, 0 , 4096)) != 0)
DoSomething(buffer, 0, len);
可以改写为:
char buffer = char[4096];
for(int len = tr.Read(buffer, 0, 4096); len != 0; len = tr.Read(buffer, 0, 4096))
DoSomething(buffer, 0, len);
有时它可能会DoSomething()
以较小的大小调用,但如果有另一个线程参与为下一次调用提供数据,它也可以具有更好的并发性Read()
。
然而,在大多数情况下,收益并不大。如果您确实需要一定数量的字符,请调用ReadBlock()
. 最重要的是,在那些与检查它是否已经完成的开销Read()
相同的情况下,它的开销非常小。不要试图在给定的情况下事后猜测是否安全;如果它需要then use的保证。ReadBlock()
ReadBlock()
Read()
ReadBlock()
ReadBlock()
这是网络流的一个主要问题,特别是如果流数据非常大并且提供流的服务器作为分块输出(即非常典型的 HTTP)这样做,因为Read()
一旦 EOS 是对单个字符读取的调用会给出 -1到达时,Read(char[], int, int)
如果到达 EOS,则使用参数调用的字符数最多为所要求的字符数或更少,然后返回读取的字符数,如果已到达 EOS,则返回零
而ReadBlock()
等待数据从流中可用,所以你永远不会遇到这个问题。
需要注意的另一件事是,这两种形式都可以读取最大数量的字符,并且如果没有那么多可用字符,则不能保证返回那么多字符
前段时间我问了一个关于类似主题的问题 -从 HttpResponseStream 读取失败- 当我从 HTTP 流读取时遇到问题