StreamReader がバッファリングを行わないようにする方法はありますか?
バイナリまたはテキストのいずれかである可能性のあるプロセスからの出力を処理しようとしています。出力はHTTPレスポンスのようになります。例:
Content-type: application/whatever
Another-header: value
text or binary data here
私がやりたいのは、 を使用してヘッダーを解析しStreamReader
、それから または から読み取ってBaseStream
残りStreamReader
のコンテンツを処理することです。基本的に私が始めたのは次のようなものです。
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 がある場所に戻すように指示できますか?
ベストアンサー1
この回答は遅く、おそらくあなたにはもう関係ないかもしれませんが、この問題に遭遇した他の誰かにとっては役に立つかもしれません。
私の問題はPPM ファイル次のような類似した形式になります。
- 先頭のASCIIテキスト
- ファイルの残りのバイナリバイト
私が遭遇した問題は、StreamReader
クラスがバッファリングせずに 1 バイトずつ読み取ることができないことでした。メソッドはRead()
1 バイトではなく 1 文字を読み取るため、場合によっては予期しない結果が発生しました。
私の解決策は、ストリームの周りにバイトを 1 つずつ読み取るラッパーを作成することでした。ラッパーには 2 つの重要なメソッドがありReadLine()
ますRead()
。
これら 2 つの方法を使用すると、ストリームの ASCII 行をバッファリングせずに読み取り、残りのストリームを 1 バイトずつ読み取ることができます。必要に応じて調整する必要があるかもしれません。
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();
}
}