Сокеты и потоки — Смешивание StreamReader и BinaryReader

#c# #.net-3.5 #stream

#c# #.net-3.5 #поток

Вопрос:

Я работаю с подключением к сокету — чтобы упростить задачу, я получаю NetworkStream сокета и оборачиваю его в StreamReader, что упрощает работу с преимущественно текстовым содержимым, которое мой сокет получает с сервера.

Однако бывают случаи, когда сервер отправляет двоичную информацию, например:

 TEXT
MORETEXT
500 BYTES OF BINARY DATA FOLLOWS THIS LINE
{500 bytes of binary data}
  

Я отлично считываю текстовое содержимое с помощью StreamReader, но поскольку StreamReader имеет свой собственный буфер, это означает, что StreamReader захватывает двоичные данные до того, как я смогу переключиться на BinaryReader для чтения 500 байт двоичных данных.

Есть ли способ обойти это? Я хотел бы иметь возможность читать текстовые данные, сохраняя при этом возможность чтения двоичных данных.

Комментарии:

1. Я использую C # в .NET 3.5, FWIW.

Ответ №1:

Мне следует провести свое исследование получше; оказывается, что класс BinaryReader уже содержит методы обработки строк и символов (хотя ему нужно несколько, например ReadLine, которые можно легко добавить, создав его подкласс).

Тогда странно, почему BinaryReader не создает подкласс TextReader, поскольку он более чем способен.

Ответ №2:

Вот расширение BinaryReader, которое вы можете использовать для выполнения ReadLine и обычных функций BinaryReader.

 public class LineReader : BinaryReader
{
    private Encoding _encoding;
    private Decoder _decoder;

    const int bufferSize = 1024;
    private char[] _LineBuffer = new char[bufferSize];

    public LineReader(Stream stream, int bufferSize, Encoding encoding)
        : base(stream, encoding)
    {
        this._encoding = encoding;
        this._decoder = encoding.GetDecoder();
    }

    public string ReadLine()
    {
        int pos = 0;

        char[] buf = new char[2];

        StringBuilder stringBuffer = null;
        bool lineEndFound = false;

        while(base.Read(buf, 0, 2) > 0)
        {
            if (buf[1] == 'r')
            {
                // grab buf[0]
                this._LineBuffer[pos  ] = buf[0];
                // get the 'n'
                char ch = base.ReadChar();
                Debug.Assert(ch == 'n');

                lineEndFound = true;
            }
            else if (buf[0] == 'r')
            {
                lineEndFound = true;
            }                    
            else
            {
                this._LineBuffer[pos] = buf[0];
                this._LineBuffer[pos 1] = buf[1];
                pos  = 2;

                if (pos >= bufferSize)
                {
                    stringBuffer = new StringBuilder(bufferSize   80);
                    stringBuffer.Append(this._LineBuffer, 0, bufferSize);
                    pos = 0;
                }
            }

            if (lineEndFound)
            {
                if (stringBuffer == null)
                {
                    if (pos > 0)
                        return new string(this._LineBuffer, 0, pos);
                    else
                        return string.Empty;
                }
                else
                {
                    if (pos > 0)
                        stringBuffer.Append(this._LineBuffer, 0, pos);
                    return stringBuffer.ToString();
                }
            }
        }

        if (stringBuffer != null)
        {
            if (pos > 0)
                stringBuffer.Append(this._LineBuffer, 0, pos);
            return stringBuffer.ToString();
        }
        else
        {
            if (pos > 0)
                return new string(this._LineBuffer, 0, pos);
            else
                return null;
        }
    }

}