混合StreamReader.Read ...和Stream.Read

时间:2014-04-02 01:10:05

标签: .net sockets stream streamreader

我有一个用于RTSP通信的TCP套接字。 由于数据是基于行的文本数据和字节大小的块的混合,我将StreamReader附加到tcpClient.GetStream(),并在文本数据需要时调用.ReadLine()

当我需要读取响应主体时,我有一个固定的字节数,所以我尝试使用stream.Read(),但这些阻塞,大概是因为StreamReader已经将数据读入自己的缓冲区。由于这是字符编码,它只读取固定数量的字符而不是字节。

有没有什么方法可以从流中读取固定数量的字节而不会完全删除StreamReader或者希望二进制数据/内容是7位安全的(反过来又不会解码)作为UTF-8)? 另一种方法是将StreamReader的编码设置为ASCII,但这可能会破坏定义为UTF-8的其余协议。

设定:

this.rtspStream = this.rtspSocket.GetStream();
this.rtspReader = new StreamReader(this.rtspStream, Encoding.UTF8);

文字阅读:

string line;
while ((line = this.rtspReader.ReadLine()) != string.Empty) {
    // ...
}

二进制阅读:

byte[] responseBody = new byte[contentLength];
this.rtspStream.Read(responseBody, 0, contentLength);

2 个答案:

答案 0 :(得分:4)

查看StreamReader源,无法混合使用StreamReader并直接从流中读取字节,因为StreamReader将字节读入其内部缓冲区然后将所有内容解码为可供阅读的字符缓冲区。

将缓冲区大小设置为0并不会有帮助,因为它会将此值强制设置为最小128个字节。

对于我的使用,我需要完全废弃StreamReader并将ReadLine()替换为直接从流中读取的内容以便自我解析。

private string ReadLine() {
    // Stringbuilder to insert the read characters in to
    StringBuilder line = new StringBuilder();

    // Create an array to store the maximum number of bytes for a single character
    byte[] bytes = new byte[this.encoding.GetMaxByteCount(1)];
    int byteCount = 0;

    while (true) {
        // Read the first byte
        bytes[0] = (byte)this.rtspStream.ReadByte();
        byteCount = 1;

        // If the encoding says this isn't a full character, read until it does
        while (this.encoding.GetCharCount(bytes, 0, byteCount) == 0) {
            bytes[byteCount++] = (byte)this.rtspStream.ReadByte();
        }

        // Get the unencoded character
        char thisChar = this.encoding.GetChars(bytes, 0, byteCount)[0];

        // Exit if it's a new line (/r/n or /n)
        if (thisChar == '\r') { continue; }
        if (thisChar == '\n') { break; }

        line.Append(thisChar);
    }
    return line.ToString();
}

答案 1 :(得分:1)

我认为您已经处理了所有标头,包括可能的Content-Length标头。我假设你现在想要阅读内容正文,这可能是也可能不是文本内容。

我认为您能够做的最好的事情是以流形式阅读整个内容主体,然后在内容为文本的情况下将内容包装在StreamReader中:

List<string> lines = new List<string>();
byte[] responseBody = new byte[contentLength];
this.rtspStream.Read(responseBody, 0, contentLength);
if (contentIsText)
{
    using (var memoryStream = new MemoryStream(responseBody, 0, contentLength))
    {
        using (var reader = new StreamReader(memoryStream))
        {
            string line;
            while ((line = reader.ReadLine()) != string.Empty)
            {
                lines.Add(line);
            }
        }
    }
    // Do something with lines
}
else
{
    // Do something with responseBody
}