I would like to know of a situation Read(char[],int,int) fails to return all chars requested while ReadBlock() returns all chars as expected (say when StreamReader works with an instance of a FileStream object).
-
You will likely only encounter this on network streams (etc), but rarely, if ever, on a FileStream. OTOH, the console's input stream could cause such a 'problem'. – leppie Sep 28 '10 at 07:23
-
Additionally, as the docs say, `ReadBlock` will wait till all the data has been read. – leppie Sep 28 '10 at 07:24
2 Answers
In practice, when using a StreamReader
it is only likely to happen with a stream which may delay for some time - e.g. a network stream as people have mentioned here.
However, with a TextReader
generally, you can expect it to happen at any time (including possibly with a future version of .NET in a case where it doesn't currently happen - that it doesn't happen with StreamReader
backed on FileStream
isn't documented, so there's no guarantee it won't happen in the future).
In particular there are a lot of cases where it's easier (with a knock on effect of simpler, more reliable and probably more efficient code) for the implementer to not return the requested amount if they can partially fulfil the call with just emptying the current buffer, or by using the amount requested as the amount to pass to a backing source (a stream or another TextReader
) before doing an operation that could only return a lower number of characters.
Now, to answer the actual question as to "When to use StreamReader.ReadBlock()?" (or more generally, when to use TextReader.ReadBlock()). The following should be borne in mind:
Both
Read()
andReadBlock()
are guaranteed to return at least one character unless the entire source has been read. Neither will return 0 if there is pending content.Calling
ReadBlock()
whenRead()
will do is wasteful, as it loops needlessly.But on the other hand it's not that wasteful.
But on the third hand, the cases where
Read()
will return fewer than requested characters are often cases where another thread is engaged in getting the content that will fill the buffer for the next call, or where that content doesn't exist yet (e.g. user input or a pending operation on another machine) - there's better overall concurrency to be found in processing the partial result and then callingRead()
again when that's finished.
So. If you can do something useful with a partial result, then call Read()
and work on what you get. In particular if you are looping through and working on the result of each Read()
then do this rather than with ReadBlock()
.
A notable case is if you are building your own TextReader that is backed by another. There's no point calling ReadBlock()
unless the algorithm really needs a certain number of characters to work - just return as much as you can from a call to Read()
and let the calling code call ReadBlock()
if it needs to.
In particular, note that the following code:
char buffer = char[4096];
int len = 0;
while((len = tr.ReadBlock(buffer, 0 , 4096)) != 0)
DoSomething(buffer, 0, len);
Can be rewritten as:
char buffer = char[4096];
for(int len = tr.Read(buffer, 0, 4096); len != 0; len = tr.Read(buffer, 0, 4096))
DoSomething(buffer, 0, len);
It may call DoSomething()
with smaller sizes sometimes, but it can also have better concurrency if there's another thread involved in providing the data for the next call to Read()
.
However, the gain is not major in most cases. If you really need a certain number of characters, then do call ReadBlock()
. Most importantly in those cases where Read()
will have the same result as ReadBlock()
the overhead of ReadBlock()
checking that it has done so is very slight. Don't try to second-guess whether Read()
is safe or not in a given case; if it needs the guarantee of ReadBlock()
then use ReadBlock()
.

- 110,372
- 10
- 146
- 251
-
1
-
1@Robino or "on the gripping hand" if you prefer your techie slang to have some classic SF references. – Jon Hanna Jan 13 '15 at 15:28
It's a major issue on network streams particularly if the Streamed data is quite large and the server providing the Stream does so as chunked output (i.e. quite typical with HTTP) since a call to just Read()
i.e. the single character read gives -1 once the EOS is reached, calls to Read(char[], int, int)
with arguments gets up to the number of characters asked for or less if the EOS is reached and then returns the number of characters read or zero if the EOS has been reached
Whereas ReadBlock()
waits for data to be available from the Stream so you never run into this issue.
One other thing to note is that both forms reads a maximum number of characters and are not guaranteed to return that many characters if there aren't that many available
I asked a question on a similar topics some time ago - Reading from a HttpResponseStream fails - when I had issues reading from HTTP streams
-
'since Read() would return a -1 for the end of stream once it reaches the end of the buffered data even if all the data from the stream had not been received'. No it wouldn't. It would return the final number of bytes received and then the EOS indication. You would never lose data. – user207421 Sep 28 '10 at 08:01
-
– Thanks for your input! But I’m not sure if ReadBlock() waits anymore if Read() returns EOS indication. I thought ReadBlock()’s waiting logic is implemented through repeated calls to Read() till it collects all the chars requested or hits EOS. Or is it not? – RanC Sep 28 '10 at 11:37
-
@EJP sorry I kinda paraphrased a bit there - I know you would not lose data – RobV Sep 28 '10 at 11:44
-
@RanC not sure how it's implemented internally but I use the ReadBlock() approach for handling network streams and don't have any issues – RobV Sep 28 '10 at 11:45
-