Клонировать байты чтения BinaryReader

Я использую BinaryReader для анализа определенных данных. Я хотел бы скопировать прочитанные байты во вторичный поток. Как я могу это сделать?

Если я унаследовал от BinaryReader (на самом деле мне это нужно сделать по другой причине), какие методы мне нужно перезаписать для правильного поведения?


person mafu    schedule 22.03.2015    source источник
comment
Уважаемый, опровергающий голосование: Не могли бы вы объяснить, в чем проблема? Это дубликат (хотя я не нашел его в поиске)?   -  person mafu    schedule 23.03.2015
comment
Не выводить, инкапсулировать. Создайте новый класс потока и создайте BinaryReader над этим потоком, в то время как ваш собственный класс обернет внутренний поток в себя. Поэтому, когда BinaryReader вызывает Read, он будет в вашем потоке, который будет выполнять чтение из базового потока и записывать прочитанные данные в другой поток во время той же Read операции.   -  person Luaan    schedule 23.03.2015


Ответы (2)


BinaryReader не настоящий _2 _... Это скорее наложение на другой поток. Вы могли:

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
    }
}

Если вы просто хотите скопировать поток в другой поток во время его чтения, вы можете использовать что-то вроде:

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; }
    }
}

Вам нужно будет реализовать / throw NotImplementedException() многие другие методы, потому что Stream - это abstract class. Щелкните правой кнопкой мыши Stream, Implement Abstract Class ускорит это.

Основное использование:

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 
}

Обратите внимание, что создание подклассов BinaryReader довольно сложно, потому что каждый метод загружает данные по-разному, поэтому нет единой «точки перехвата».

person xanatos    schedule 22.03.2015
comment
Боюсь, у меня это не сработает, потому что источник недоступен для поиска (это сетевой поток). - person mafu; 23.03.2015
comment
В этом примере MemoryStream - это место, куда вы копируете данные. Где есть bw.Write, у вас сначала должна быть br.Read из вашего стрима - person xanatos; 23.03.2015
comment
Верно. Но я использую много операций чтения, поэтому хочу автоматизировать процесс клонирования данных. - person mafu; 23.03.2015
comment
Правильно. Это то, что я искал. Но возникает вопрос: какие методы мне нужно переопределить? Я почти уверен, что мне нужно переопределить только некоторые из них, поскольку они используются повторно внутри компании. Но какие? - person mafu; 23.03.2015
comment
@mafu Два Read, которые я написал, и Dispose(bool disposing), если вы хотите, чтобы другие ваши потоки автоматически удалялись. Stream.Close вызывает Dispose(bool disposing), так что Stream.Close уже в порядке. Для всего остального ... Писать нечего ... А потом, если есть, получишь NotImplementedException и найдешь :-) - person xanatos; 23.03.2015
comment
Хорошо, было бы здорово, если бы использовались только эти два метода. Но я не уверен, почему должен быть NIE - я создаю подкласс только от BinaryReader, поэтому все другие методы остаются нетронутыми (но они должны надеюсь использовать обновленные методы ReadByte / ReadBytes). - person mafu; 23.03.2015
comment
Позвольте нам продолжить это обсуждение в чате. - person xanatos; 23.03.2015
comment
Исправление: я обнаружил, что ReadByte не следует перезаписывать, так как он внутренне вызывает Read. (Луаан понял это правильно) - person mafu; 24.03.2015
comment
@mafu Ошибка была моя, в общем, ReadByte () должен вызывать ReadStream.ReadByte, а не base.ReadByte. Я не уверен, что все потоки вызывают из ReadByte Read (byte []). Исправлено при последнем редактировании - person xanatos; 24.03.2015

Потоки предназначены для инкапсуляции, а не переопределения:

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(); }
}

Затем вместо создания BinaryReader поверх базового потока вы создаете его поверх DuploStream, передавая базовый поток и поток копирования.

person Luaan    schedule 23.03.2015