Zain Rizvi
Zain Rizvi

Reputation: 24676

.Net BinaryWriter automatically flushes stream when checking stream Position

Has anyone else seen this or know how to turn this off?

I have code which periodically checks the Position of a stream in a BinaryWriter. Every invocation of the BinaryWriter.BaseStream.Position method results in that stream's Flush method being invoked.

I tried using a BinaryWriter and a StreamWriter, and only the BinaryWriter demonstrated this behavior.

Some sample code below:

namespace FlushaholicStreams
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var stream = new PrivateStream())
            using (var writer = new BinaryWriter(stream))
            {
                var data = "hi there, this is a really long string. Very very very long";

                for (int i = 0; i < 19; i++)
                {
                    data += data;
                }

                for (int j = 0; j < 8; j++)
                {
                    var bytes = Encoding.ASCII.GetBytes(data);
                    writer.Write(bytes);
                    var position = writer.BaseStream.Position;
                    Console.WriteLine("The position was {0}", position);
                }
            }

            Console.WriteLine("All done");
        }
    }

    class PrivateStream : MemoryStream
    {
        public int FlushCount = 0;
        public int CloseCount = 0;

        public override void Close()
        {
            this.CloseCount++;
            Console.WriteLine("Closing the stream");
            base.Close();
        }

        public override void Flush()
        {
            this.FlushCount++;
            Console.WriteLine("Flushing the stream");
            base.Flush();
        }
    }
}

That code yields the output:

Flushing the stream
The position was 30932992
Flushing the stream
The position was 61865984
Flushing the stream
The position was 92798976
Flushing the stream
The position was 123731968
Flushing the stream
The position was 154664960
Flushing the stream
The position was 185597952
Flushing the stream
The position was 216530944
Flushing the stream
The position was 247463936
Flushed the stream 8 times
Closing the stream
Closing the stream
All done

I'm using .Net 4.5

Upvotes: 2

Views: 634

Answers (2)

Zain Rizvi
Zain Rizvi

Reputation: 24676

Looks like the BinaryWriter class forces excessive Flushing and there's no way to override it. I'll just keep a reference to the original stream and check position on it directly.

I found the (alleged) source code here:

http://reflector.webtropy.com/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/clr/src/BCL/System/IO/BinaryWriter@cs/1305376/BinaryWriter@cs

/* 
* Returns the stream associate with the writer. It flushes all pending
* writes before returning. All subclasses should override Flush to 
* ensure that all buffered data is sent to the stream.
*/
public virtual Stream BaseStream {
  get { 
    Flush();
    return OutStream; 
  } 
}

// Clears all buffers for this writer and causes any buffered data to be
// written to the underlying device.
public virtual void Flush()
{ 
  OutStream.Flush();
} 

Upvotes: 1

usr
usr

Reputation: 171246

The framework is prone to flushing, yes. That's bad because it forces disk access. (Subjective note: It's a design flaw.)

Write yourself a Stream that wraps another stream. In your wrapper class you override the necessary methods to maintain the Position yourself in an instance field. That way the Position member of the wrapped stream does not need to be accessed at all.

Upvotes: 0

Related Questions