Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to use Stream.Seek when a BinaryReader is open?

Because of the under the hood buffering strategy of BinaryReader, it is unclear to me whether is it ok or not to read an offset stored in a stream, then reposition the stream at this offset to resume the streaming.

As an example, is the following code ok:

using (var reader = new CustomBinaryReader(inputStream))
{
   var offset= reader.ReadInt32();
   reader.BaseStream.Seek(offset, SeekOrigin.Begin);

   //Then resume reading the streaming
}

Or should I close the first binary reader before Seeking the stream and then reopen a second reader ?

int offset;
using (var firstReader = new CustomBinaryReader(inputStream))
{
   offset= firstReader.ReadInt32();
}
inputStream.Seek(offset, SeekOrigin.Begin);
using (var secondReader = new CustomBinaryReader(inputStream))
{
   //Then resume reading the streaming
}
like image 489
Matthieu Durut Avatar asked Oct 02 '13 09:10

Matthieu Durut


People also ask

What is seek in stream?

SeekOrigin Enum (System.IO)Specifies the position in a stream to use for seeking.

What is BinaryReader?

The BinaryReader class provides methods that simplify reading primitive data types from a stream. For example, you can use the ReadBoolean method to read the next byte as a Boolean value and advance the current position in the stream by one byte. The class includes read methods that support different data types.

How BinaryReader works in c#?

In C#, BinaryReader is a class used to handle binary data. It is found under System.IO namespace. BinaryReader is used to read primitive data types as binary values in a particular encoding stream.

What is seek in c#?

This C# method locates a position in a file. It allows data to be read from a binary file at a certain part. For example, we can read 20,000 bytes from any part of a file.


2 Answers

I would say that it is not always safe (although it might be safe in some cases).

The Microsoft documentation for BinaryReader.BaseStream explicitly states:

Using the underlying stream while reading or while using the BinaryReader can cause data loss and corruption. For example, the same bytes might be read more than once, bytes might be skipped, or character reading might become unpredictable.

So I would avoid it.

(Interestingly, there's a BinaryWriter.Seek() method, but no BinaryReader.Seek().)

like image 55
Matthew Watson Avatar answered Nov 15 '22 16:11

Matthew Watson


BinaryReader does use a buffer but only to read enough bytes from the base stream to convert a value. In other words, ReadInt32() will buffer 4 bytes first, ReadDecimal() will buffer 16 bytes first, etcetera. ReadString() is the trickier method but it has counter-measures as well, a string is encoded in the file by BinaryWriter which writes the string length first. So that BinaryReader knows exactly how many bytes to buffer before converting the string.

So the buffer is always empty after one of the ReadXxx() method returns and calling Seek() on the BaseStream is fine. Also the reason that Microsoft didn't need to override the Seek() method.

The cautionary note in the MSDN article is appropriate, you certainly will read that "offset" value more than once if you call a ReadXxx() method after the Seek() call. I however assume that was entirely intentional.

like image 37
Hans Passant Avatar answered Nov 15 '22 15:11

Hans Passant