ReadLine on Binary Stream

When you are reading data from a binary stream, like NetworkStream or FileStream and you need to read both binary chunks as well as read one text line at a time, you are on your own as BinaryReader nor Stream supports ReadLine. You can use StreamReader to do ReadLine, but it does not allow you [...]

Editorial Note

This article appears in the Third Party Product Reviews section. Articles in this section are for the members only and must not be used by tool vendors to promote or advertise products in any way, shape or form. Please report any spam or advertising.

When you are reading data from a binary stream, like NetworkStream or FileStream and you need to read both binary chunks as well as read one text line at a time, you are on your own as BinaryReader nor Stream supports ReadLine. You can use StreamReader to do ReadLine, but it does not allow you to read chunks of bytes. The Read(byte[], int, int) is not there on StreamReader.

Here’s an extension of BinaryReader for doing ReadLine over a binary stream. You can read both byte chunks, as well as read text lines at the same time.

Why not just use two streams? Create your base stream, then create the BinaryReader and StreamReader using the base stream. You can then perform both operations on the stream and the base stream keeps track of the position. For example:

You are also using Debug.Assert for control flow which is a bad idea, there are legitimate reasons for having a '\r' in a string without the corresponding '\n'. If you compile it in release mode, the Debug.Assert's all go away. Also, by reading two characters at a time and checking you may end up dropping legitimate data if the '\r' appears as the first character. A better method would be to use the peek methods to get the next character without advancing the stream pointer.

I wish life was that easy my friend. Just try calling StreamReader.ReadLine and then try reading using BinaryReader.Read. You will see it is reading way past the first line.

StreamReader.ReadLine does not just read one line from the Base stream, it reads a byte[] chunk and then converts that to char[] and then looks for \r\n inside that char[]. It always reads a buffer at a time from the basestream. You can use a decompiler to see the code inside ReadLine.

Thus when BinaryReader.Read is called, the base stream position is already way ahead, and it reads bytes from the last buffer position by StreamReader.ReadLine.

On the second point, Debug.Assert is never used to control flow. It is to test something during debugging. I am using that to make sure my algorithm is correct and \n is really there where I am expecting. Otherwise the code breaks and I know there's something wrong in my algorithm. Debug.Assert isn't a functional code. It is a debugging helper.