StreamReader Unbuffered

¿Hay alguna manera de evitar que StreamReader realice cualquier almacenamiento en búfer?

Estoy tratando de manejar la salida de un proceso que puede ser binario o de texto. La salida se verá como una respuesta HTTP, por ejemplo,

Content-type: application/whatever Another-header: value text or binary data here 

Lo que quiero hacer es analizar los encabezados con un StreamReader , y luego leer desde su BaseStream o StreamReader para manejar el rest del contenido. Esto es básicamente lo que empecé con:

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

Esto parece desechar datos binarios. Así que cambié la última línea a algo como esto:

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

… pero StreamReader regula su entrada, por lo que reader.BaseStream está en la posición incorrecta. ¿Hay una manera de desempañar StreamReader? ¿O puedo decirle a StreamReader que restablezca la secuencia a donde está StreamReader?

Esta respuesta es tardía y posiblemente ya no sea relevante para usted, pero puede ser útil para alguien que se encuentre con este problema.

Mi problema involucraba archivos PPM , que tienen un formato similar de:

  • Texto ASCII en el principio
  • Bytes binarios para el rest del archivo.

El problema que encontré fue que la clase StreamReader es incapaz de leer cosas de un byte a la vez sin cosas de almacenamiento intermedio. Esto causó resultados inesperados en algunos casos, ya que el método Read() lee un solo carácter, no un solo byte.

Mi solución fue escribir una envoltura alrededor de una secuencia que leyera los bytes uno a la vez. La envoltura tiene 2 métodos importantes, ReadLine() y Read() .

Estos 2 métodos me permiten leer las líneas ASCII de un flujo, sin almacenamiento en búfer, y luego leer un solo byte a la vez durante el rest del flujo. Es posible que necesite hacer algunos ajustes para satisfacer sus necesidades.

 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 bytes = new List(); 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(); } } 

Bueno, puedes usar Stream.Seek para establecer la posición de la secuencia. Me parece que el problema que está teniendo aquí es que StreamReader está leyendo caracteres en lugar de bytes (que, según la encoding, pueden ser diferentes de 1 byte por carácter). Desde la biblioteca de MSDN :

StreamReader está diseñado para la entrada de caracteres en una encoding particular, mientras que la clase Stream está diseñada para la entrada y salida de bytes.

Cuando llama a reader.ReadToEnd (), lee los datos como una cadena de caracteres según la encoding que esté usando. Es posible que tenga mejor suerte con el método Stream.Read . Lea sus datos de cadena con StreamReader y luego extraiga los datos binarios en un byte [] cuando haya leído en el encabezado que le notifica los datos binarios entrantes.