代码之家  ›  专栏  ›  技术社区  ›  Matt Burke

无缓冲流阅读器

  •  17
  • Matt Burke  · 技术社区  · 17 年前

    有没有办法阻止StreamReader进行任何缓冲?

    我试图处理一个进程的输出,这个进程可以是二进制的,也可以是文本的。输出看起来像HTTP响应,例如。

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

    我要做的是使用 StreamReader BaseStream 或者 流阅读器 处理其余内容。基本上我是这样开始的:

    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所在的位置吗?

    2 回复  |  直到 17 年前
        1
  •  9
  •   Dan Herbert    16 年前

    这个答案是迟来的,可能不再与你有关,但它可能会派上用场的其他人谁偶然发现这个问题。

    我的问题牵涉其中 PPM files ,其格式类似于:

    • ASCII文本开头

    我遇到的问题是 StreamReader Read() 方法读取单个字符,而不是单个字节。

    我的解决方案是围绕一个流编写一个包装器,一次读取一个字节。包装器有两个重要的方法, ReadLine() 和 读取() .

    这两种方法允许我读取流的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();
        }
    }
    
        2
  •  0
  •   Stuart Childs    17 年前

    好吧,你可以用 Stream.Seek 设置流的位置。在我看来,您在这里遇到的问题是StreamReader读取的是字符而不是字节(根据编码的不同,每个字符可能不同于1字节)。从 MSDN Library

    StreamReader是为字符 以特定编码输入, 而Stream类 用于字节输入和输出。

    当您调用reader.ReadToEnd()时,它将根据所使用的编码以字符串的形式读取中的数据。你可能会更幸运的使用 Stream.Read