When to use .NET BufferedStream class?

.NetPerformanceBuffer

.Net Problem Overview


The MSDN site states:

> A buffer is a block of bytes in memory > used to cache data, thereby reducing > the number of calls to the operating > system. Buffers improve read and write > performance. A buffer can be used for > either reading or writing, but never > both simultaneously. The Read and > Write methods of BufferedStream > automatically maintain the buffer.

Should I use this class in every possible occasion?

.Net Solutions


Solution 1 - .Net

According to Brad Abrams, almost never: link

> No, there is zero benefit from wrapping a BufferedStream around a > FileStream. We copied BufferedStream’s buffering logic into > FileStream about 4 years ago to encourage better default > performance... In fact, I don’t think there are any Streams in the > .NET Framework that require it, but it might be needed by custom > Stream implementations if they do not do buffering by default.

Solution 2 - .Net

The following is some text from an online course I am taking: > The BufferedStream class is a concrete > class that extends the Stream class > and is used to provide an additional > memory buffer to another type of > stream, both synchronously and > asynchronously. The BufferedStream > class must be configured to either > read or write when an instance of the > class is created, but the > BufferedStream cannot be configured to > perform both the tasks at the same > time. > > Microsoft improved the performance of > all streams in the .NET Framework by > including a built-in buffer. The > performance noticeably improved by > applying a BufferedStream to existing > streams, such as a FileStream or > MemoryStream. Applying a > BufferedStream to an existing .NET > Framework stream results in a double > buffer. > > The most common application of the > BufferedStream class is in custom > stream classes that do not include a > built-in buffer.

Solution 3 - .Net

Best case I know of is when BinaryFormatter serialize/deserialize directly from NetworkStream. Use of BufferedStream inbetween increase performance tenfold.

Solution 4 - .Net

The normal file I/O streams are already buffered by using a StreamReader/StreamWriter.

Since read/write operations on streams, normally use the Read/Write methods that take a byte array, you will naturally provide some buffering yourself.

If you use very small arrays, or use WriteByte, you might get better performance by using a BufferedStream in between.

Solution 5 - .Net

Late answer but going to answer it anyways. If you understand how it works you can understand why it makes no sense to use in some cases and why it makes sense to not use in other cases.

To proof this I am using StreamWrapper class. Only use this class to see how many times you hit a breakpoint! Place breakpoints all over this class. Our goal is to see how many times we call the Write, Read, and other methods.

// This class is only used for demo purposes. Place a breakpoint on all parts
class StreamWrapper : Stream
{
    Stream stream;

    public StreamWrapper(Stream s)
    {
        stream = s;
    }

    public override bool CanRead => stream.CanRead;

    public override bool CanSeek => stream.CanSeek;

    public override bool CanWrite => stream.CanWrite;

    public override long Length => stream.Length;

    public override long Position { get => stream.Position; set => stream.Position = value; }

    public override void Flush()
    {
        stream.Flush();
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        return stream.Read(buffer, offset, count);
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        return stream.Seek(offset,origin);
    }

    public override void SetLength(long value)
    {
        stream.SetLength(value);
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        stream.Write(buffer, offset, count);
    }

    
}

Now that you have that wrapper class that is basically a wrapper to an existing strem you may do the following tests:

Example Writting:

// in real life you want this to be larger. 
int bufferSize = 8;


// Use BufferedStream to buffer writes to a MemoryStream.
using (var memory_test = new StreamWrapper(new MemoryStream()))
using (BufferedStream stream = new BufferedStream(memory_test, bufferSize))
{


    // all this will only send one write to memory_test!
    stream.Write(new byte[] { 1, 2 });
    stream.Write(new byte[] { 1, 2 });
    stream.Write(new byte[] { 1, 2 });
    stream.Write(new byte[] { 1, 2 });
    // BREAKPOINT ONLY HITS ONE TIME 


    // All this will also send only one write to memory_test
    for (int i = 0; i < 8; i++)                            
        stream.WriteByte(5);
    // BREAKPOINT ONLY HITS ONE TIME AGAIN INSTAD OF 8


    // this will send one write to memory_test. Writes of more than 8 bytes can happen!
    stream.Write(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 });
    // ALL THIS WILL SEND ONE WRITE AGAIN
}

Example reading:

// example reading
{
    // create stream with some data in it that we will be reading
    var ms = new MemoryStream();
    {
        // Write 256 bytes
        for (int i = 0; i <= byte.MaxValue; i++)
        {
            ms.WriteByte((byte)i);
        }
        ms.Position = 0;
    }

    // Use BufferedStream to buffer writes to a MemoryStream.
    using (var memory_test = new StreamWrapper(ms))
    {                                                        
        using (BufferedStream stream = new BufferedStream(memory_test, 8))
        {
            // note I do not care about the output of each read for demo breakpoint. On real life you will store that output
            // for now we only care how many times we hit the breakpoint because on real life that could be a slow/expensive 
            // operation such as opening a file for writing and you want to do those as few as possible.

            // hit breakpoint only one time with all this reads
            stream.ReadByte();
            stream.ReadByte();
            stream.ReadByte();
            stream.ReadByte();
            stream.ReadByte();
            stream.ReadByte();
            stream.ReadByte();
            stream.ReadByte();


            // hit breakpoint only one time with all this reads
            stream.Read(new byte[2] );
            stream.Read(new byte[2] );
            stream.Read(new byte[2] );
            stream.Read(new byte[2] );


            // hit breakpoint only one time even though it is larger than our buffer size 8
            // our goal is to hit the breakpoint as fewest time as possible because in real life
            // this could be slow/expensive operations
            stream.Read(new byte[1024] );

        }
    }
}

If this where to be write operations to a file for example performance could increase by ensuring you always write at least 8 bytes instead of 1 at a time. In real life you want this number to be about 4 KB

Solution 6 - .Net

What must be used in every possible occasion is common sense. There's no use in utilizing this class when reading-writing to-from a MemoryStream, but it might be quite useful when doing network or disk IO (if Streams for these subsystems do not do buffering on their own).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJader DiasView Question on Stackoverflow
Solution 1 - .NetdewaldView Answer on Stackoverflow
Solution 2 - .NethackerView Answer on Stackoverflow
Solution 3 - .NetidnView Answer on Stackoverflow
Solution 4 - .NetGvSView Answer on Stackoverflow
Solution 5 - .NetTono NamView Answer on Stackoverflow
Solution 6 - .NetAnton GogolevView Answer on Stackoverflow