2009-02-06 13 views
17

Gibt es eine Möglichkeit, StreamReader von einer Pufferung abzuhalten?Unbuffered StreamReader

Ich versuche, Ausgabe von einem Prozess zu behandeln, der binär oder Text sein kann. Die Ausgabe wird wie eine HTTP-Antwort aussehen, z.

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

text or binary data here 

Was ich tun möchte, ist die Header analysieren eine StreamReader verwenden, und dann lesen Sie entweder von seinem BaseStream oder StreamReader den Rest des Inhalts zu behandeln. Hier ist im Grunde, was ich angefangen habe:

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

Dies scheint Binärdaten zu löschen. Also änderte ich die letzte Zeile in etwa so:

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

... aber Stream puffert seine Eingabe, so reader.BaseStream in der falschen Position. Gibt es eine Möglichkeit, StreamReader zu entpacken? Oder kann ich StreamReader anweisen, den Stream wieder dahin zurückzusetzen, wo StreamReader ist?

+0

Matt - können Sie näher ausführen "Stream liest Blöcke zu einer Zeit, so reader.BaseStream in der falschen Position" – jro

+0

hoffentlich ist das klarer. –

Antwort

0

Nun, Sie können Stream.Seek verwenden, um die Position des Streams festzulegen. Es klingt für mich wie das Problem, das Sie hier haben, ist, dass StreamReader Zeichen anstelle von Bytes liest (die abhängig von der Codierung möglicherweise von 1 Byte pro Zeichen abweichen). Von den MSDN Library:

Streamreader für Zeichen Eingang in einer bestimmten Codierung ausgebildet ist, wird während die Stream-Klasse für Byte-Eingang und Ausgang ausgelegt.

Wenn Sie reader.ReadToEnd() aufrufen, liest es die Daten als eine Zeichenkette basierend auf der Codierung, die es verwendet. Vielleicht haben Sie mehr Glück mit der Stream.Read Methode. Lesen Sie Ihre String-Daten mit StreamReader ein und ziehen Sie dann die Binärdaten in ein Byte [], wenn Sie den Header gelesen haben, der Sie über eingehende Binärdaten informiert.

+0

Nun, Sie können nicht innerhalb von NetworkStream suchen. – nitrocaster

8

Diese Antwort ist zu spät und möglicherweise nicht mehr relevant für Sie, aber es kann für jemanden nützlich sein, der über dieses Problem stolpert.

Mein Problem beteiligt PPM files, die ein ähnliches Format haben:

  • ASCII-Text am Anfang
  • Binary Bytes für den Rest der Datei

Das Problem war ich lief in dass die Klasse StreamReader nicht in der Lage ist, ein Byte zu einem Zeitpunkt ohne Pufferung von Daten zu lesen. Dies führte in einigen Fällen zu unerwarteten Ergebnissen, da die Methode Read() ein einzelnes Zeichen und kein einzelnes Byte liest.

Meine Lösung bestand darin, einen Wrapper um einen Stream zu schreiben, der Byte für Byte lesen würde. Der Wrapper hat 2 wichtige Methoden, ReadLine() und Read().

Mit diesen beiden Methoden kann ich die ASCII-Zeilen eines Stream ungepuffert lesen und dann für den Rest des Streams jeweils ein Byte lesen. Möglicherweise müssen Sie einige Anpassungen vornehmen, um Ihren Anforderungen zu entsprechen.

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

Um Ihre Lösung zu verbessern, müssen Sie null zurückgeben, wenn die Byte-Liste leer ist, um die Definition der Basisklasse TextReader zu erfüllen. Momentan geben Sie eine leere Zeichenfolge zurück. – Doomjunky