0
votes

I'm using a BinaryReader to parse certain data. I would like to copy the read bytes to a secondary stream. How can I do that?

If I derive from BinaryReader (I need to do that for a different reason anyway, actually), which methods do I need to overwrite for correct behavior?

2
Dear downvoter: Mind explaining what the problem is? Is this a duplicate (even tho I could not find this in search)? - mafu
Do not derive, encapsulate. Create a new stream class, and create the BinaryReader over this stream, while your own class will wrap the inner stream in itself. So when BinaryReader calls Read, it will be on your stream, which will do the reading from the underlying stream, and writing the data it read to another stream during the same Read operation. - Luaan

2 Answers

2
votes

BinaryReader isn't a real Stream... It is more an overlay on another stream. You could:

using (var yourStream = /* ... */)
using (var br = new BinaryReader(yourStream))
{
    using (var ms = new MemoryStream())
    {
        // Important the true, so that the ms remains open!
        using (var bw = new BinaryWriter(ms, Encoding.UTF8, true))
        {
            var readed = br.ReadInt32();
            bw.Write(readed); 
            // All the basic types are supported by various overlaods
        }

        // Here you have your ms... If you want to reread it:
        ms.Position = 0;

        using (var br2 = new BinaryReader(ms, Encoding.UTF8, true))
        {
            // Reread it
        }

        // Or copy it to another stream, or do whatever you want
    }
}

If you simply want to duplicate a stream on another stream while you are reading it, you can use something like:

public class CopyStream : Stream
{
    // This is the stream you want to read your data from
    public Stream ReadStream { get; set; }

    // This is the "logger" stream, where a copy of read data will be put
    public Stream LogStream { get; set; }

    public override int Read(byte[] buffer, int offset, int count)
    {
        int res = ReadStream.Read(buffer, offset, count);

        if (LogStream != null)
        {
            if (res > 0)
            {
                LogStream.Write(buffer, offset, res);
            }
        }

        return res;
    }

    public override int ReadByte()
    {
        int res = ReadStream.ReadByte();

        if (LogStream != null)
        {
            if (res >= 0)
            {
                LogStream.WriteByte((byte)res);
            }
        }

        return res;
    }

    public override bool CanSeek
    {
        get { return false; }
    }
}

You'll need to implement/throw NotImplementedException() many other methods, because Stream is an abstract class. Right click on the Stream, Implement Abstract Class will speedup this.

The basic use is:

var cs = new CopyStream
    {
        ReadStream = yourStream,
        LogStream = whereyouwanttoWriteStream,
    };

using (var br = new BinaryReader(CopyStream, Encoding.UTF8, true))
{
    // Here you can read normally from the BinaryReader.
    // Everything you read will be copied to LogStream 
}

Note that subclassing BinaryReader is quite complex, because each method loads the data in a different way, so there isn't a single "point of interception".

1
votes

Streams are meant to be encapsulated, not overriden:

public class DuploStream : Stream
{
    private readonly Stream _underlyingStream;
    private readonly Stream _copyStream;

    public DuploStream(Stream underlyingStream, Stream copyStream)
    {
        _underlyingStream = underlyingStream;
        _copyStream = copyStream;
    }

    public override bool CanRead { get { return true; } }
    public override bool CanSeek { get { return false; } }
    public override bool CanWrite { get { return false; } }

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

    public override long Length { get { throw new NotSupportedException(); } }
    public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } }

    public override int Read(byte[] buffer, int offset, int count)
    {
        var bytesRead = _underlyingStream.Read(buffer, offset, count);

        _copyStream.Write(buffer, offset, bytesRead);

        return bytesRead;
    }

    public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
    public override void SetLength(long value) { throw new NotSupportedException(); }
    public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
}

Then, instead of creating BinaryReader on top of your underlying stream, you build it on top of DuploStream, passing the underlying stream and the copy stream.