What does BinaryReader do if the bytes I am reading aren't present yet?
Asked Answered
N

2

11

I am using a BinaryReader on top of a NetworkStream to read data off of a network. This has worked really well for me, but I want to understand what's going on behind the scenes, so I took a look at the documentation for BinaryReader and found it to be extremely sparse.

My question is this: What will BinaryReader.ReadBytes(bufferSize) do if bufferSize bytes are not present on the network stream when I call ReadBytes?

In my mind there are a few options:
1) Read any bytes that are present on the network stream and return only that many
2) Wait until bufferSize bytes are present on the stream, then read
3) Throw an exception

I assume option 2 is happening, since I've never received any exceptions and all my data is received whole, not in pieces. However, I would like to know for sure what is going on. If someone could enlighten me, I would be grateful.

Neves answered 30/5, 2012 at 5:31 Comment(1)
It will block and ensure you get the requested number of bytes. You only get less if the stream got closed and you have read them all.Grandnephew
M
13

I believe it actually goes for hidden option 4:

  • Read the data as it becomes available, looping round in the same way that you normally would do manually. It will only return a value less than the number of bytes you asked for if it reaches the end of the stream while reading.

This is subtly different from your option 2 as it does drain the stream as data becomes available - it doesn't wait until it could read all of the data in one go.

It's easy to show that it does return a lower number of bytes than you asked for if it reaches the end:

var ms = new MemoryStream(new byte[10]);
var readData = new BinaryReader(ms).ReadBytes(100);
Console.WriteLine(readData.Length); // 10

It's harder to prove the looping part, without a custom stream which would explicitly require multiple Read calls to return all the data.

The documentation isn't as clear as it might be, but the return value part is at least somewhat helpful:

A byte array containing data read from the underlying stream. This might be less than the number of bytes requested if the end of the stream is reached.

Note the final part that I've highlighted, and compare that with Stream.Read:

The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.

If you're expecting an exact amount of data and only that amount will be useful, I suggest you write a ReadExactly method which calls Read and throws EndOfStreamException if you need more data than the stream provided before it was closed.

Meanly answered 30/5, 2012 at 5:49 Comment(1)
Thanks for the detail in your response. I do have one quick, easy question though. The end of the stream is only reached if the stream is closed, correct?Neves
S
0

If, by “present on the stream”, you’re asking whether the method would block until the specified number of bytes are available, then it is option 2. It would only return a smaller amount of bytes if the end of the stream is reached.

Here is some sample code on how BinaryReader.ReadBytes(int) may be implemented:

byte[] ReadBytes(int count)
{
    byte[] buffer = new byte[count];
    int total = 0;
    int read = 0;

    do
    {
        read = stream.Read(buffer, read, count - total);
        total += read;
    }
    while (read > 0 && total < count);

    // Resize buffer if smaller than count (code not shown).

    return buffer;
}
Singe answered 30/5, 2012 at 5:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.