何时使用StreamReader.ReadBlock()?

我想知道一种情况Read(char [],int,int)无法返回请求的所有字符,而ReadBlock()按预期返回所有字符(例如当StreamReader与FileStream对象的实例一起工作时)。

实际上,当使用StreamReader它很可能只发生一段可能会延迟一段时间的流 – 例如人们在这里提到的网络流。

但是,通常使用TextReader ,您可以预期它会在任何时候发生(包括可能在未来版本的.NET中发生 – 当前不会发生 – 在FileStream支持的StreamReader上不会发生这种情况)记录,所以不能保证将来不会发生)。

特别是在很多情况下,如果只是清空当前缓冲区可以部分地完成调用,那么实现者不会返回请求的数量更容易(通过更简单,更可靠和可能更高效的代码的效果) ,或者在执行只能返回较少数量字符的操作之前,使用请求的金额作为传递给后备源(流或其他TextReader )的金额。

现在,回答关于“何时使用StreamReader.ReadBlock()?”的实际问题。 (或更一般地,何时使用TextReader.ReadBlock())。 应牢记以下内容:

  1. 除非已读取整个源,否则Read()ReadBlock()都保证至少返回一个字符。 如果有待处理的内容,也不会返回0。

  2. Read()执行时调用ReadBlock()是浪费的,因为它不必要地循环。

  3. 但另一方面,这并不浪费。

  4. 但是第三方面, 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()ReadBlock()具有相同结果的情况下, ReadBlock()检查它已经完成的开销非常小 。 在特定情况下,不要试图猜测Read()是否安全; 如果它需要ReadBlock()的保证,那么使用ReadBlock()

这是网络流上的一个主要问题,特别是如果流数据非常大并且提供Stream的服务器就像分块输出那样(即非常典型的HTTP),因为只调用Read()即单个字符读取给出-1一次到达EOS时,带有参数的Read(char[], int, int)调用达到要求的字符数或更少,如果达到EOS则返回读取的字符数或者如果EOS已经为零则返回零到达

ReadBlock()等待数据可从Stream获得,因此您永远不会遇到此问题。

另外需要注意的是,两个表单都会读取最大字符数,如果没有那么多字符,则无法保证返回那么多字符

前段时间我问了一个关于类似主题的问题 – 从HttpResponseStream读取失败 – 当我从HTTP流中读取问题时