2009-02-06 80 views
17

有沒有辦法讓StreamReader保持緩衝?無緩衝StreamReader

我正在嘗試處理可能是二進制或文本的進程的輸出。輸出將看起來像一個HTTP響應,例如

Content-type: application/whatever 
Another-header: value 

text or binary data here 

我想要做的是解析使用StreamReader頭,然後無論是從它的BaseStreamStreamReader讀取處理內容的其餘部分。這裏基本上是我開始的:

private static readonly Regex HttpHeader = new Regex("([^:]+): *(.*)"); 
private void HandleOutput(StreamReader reader) 
{ 
    var headers = new NameValueCollection(); 
    string line; 
    while((line = reader.ReadLine()) != null) 
    { 
    Match header = HttpHeader.Match(line); 
    if(header.Success) 
    { 
     headers.Add(header.Groups[1].Value, header.Groups[2].Value); 
    } 
    else 
    { 
     break; 
    } 
    } 
    DoStuff(reader.ReadToEnd()); 
} 

這似乎是垃圾二進制數據。所以我改變了最後一行是這樣的:

if(headers["Content-type"] != "text/html") 
{ 
    // reader.BaseStream.Position is not at the same place that reader 
    // makes it looks like it is. 
    // i.e. reader.Read() != reader.BaseStream.Read() 
    DoBinaryStuff(reader.BaseStream); 
} 
else 
{ 
    DoTextStuff(reader.ReadToEnd()); 
} 

...但StreamReader的緩衝器的輸入,所以reader.BaseStream是在錯誤的位置。有沒有一種方法來取消緩衝StreamReader?或者我可以告訴StreamReader將流重置回StreamReader所在的位置?

+0

馬特 - 你能否詳細說明「StreamReader一次讀取塊,所以reader.BaseStream處於錯誤的位置。」 – jro 2009-02-06 16:55:37

+0

希望這更清晰。 – 2009-02-06 17:36:01

回答

0

那麼,你可以使用Stream.Seek設置流的位置。在我看來,您在這裏遇到的問題是StreamReader正在讀取字符而不是字節(取決於編碼,可能與每個字符1個字節不同)。從MSDN Library

的StreamReader在特定編碼設計用於字符輸入 , 而流類是字節輸入和輸出設計 。

當你調用reader.ReadToEnd()時,它根據它使用的任何編碼讀取字符串中的數據。使用Stream.Read方法您可能會有更好的運氣。使用StreamReader讀取字符串數據,然後在讀入通知您的傳入二進制數據的標頭中時,將二進制數據提取到一個字節[]中。

+0

那麼,你不能在NetworkStream中尋找。 – nitrocaster 2015-04-08 00:56:39

8

此答案已晚,可能與您無關,但對於絆倒此問題的其他人可能會派上用場。

我的問題涉及PPM files,其中有一個類似的格式:

  • ASCII文本開始
  • 的文件

我遇到了這個問題的其餘二進制字節StreamReader類不能在不緩衝內容的情況下一次讀取一個字節的內容。這在某些情況下會導致意外的結果,因爲Read()方法讀取單個字符而不是單個字節。

我的解決方案是圍繞一個流一次寫入一個字節的包。包裝有兩個重要的方法,ReadLine()Read()

這兩種方法允許我讀取未緩衝的流的ASCII行,然後一次讀取其餘流的單個字節。您可能需要進行一些調整以適應您的需求。

class UnbufferedStreamReader: TextReader 
{ 
    Stream s; 

    public UnbufferedStreamReader(string path) 
    { 
     s = new FileStream(path, FileMode.Open); 
    } 

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

    // This method assumes lines end with a line feed. 
    // You may need to modify this method if your stream 
    // follows the Windows convention of \r\n or some other 
    // convention that isn't just \n 
    public override string ReadLine() 
    { 
     List<byte> bytes = new List<byte>(); 
     int current; 
     while ((current = Read()) != -1 && current != (int)'\n') 
     { 
      byte b = (byte)current; 
      bytes.Add(b); 
     } 
     return Encoding.ASCII.GetString(bytes.ToArray()); 
    } 

    // Read works differently than the `Read()` method of a 
    // TextReader. It reads the next BYTE rather than the next character 
    public override int Read() 
    { 
     return s.ReadByte(); 
    } 

    public override void Close() 
    { 
     s.Close(); 
    } 
    protected override void Dispose(bool disposing) 
    { 
     s.Dispose(); 
    } 

    public override int Peek() 
    { 
     throw new NotImplementedException(); 
    } 

    public override int Read(char[] buffer, int index, int count) 
    { 
     throw new NotImplementedException(); 
    } 

    public override int ReadBlock(char[] buffer, int index, int count) 
    { 
     throw new NotImplementedException(); 
    }  

    public override string ReadToEnd() 
    { 
     throw new NotImplementedException(); 
    } 
}