我有一个项目,我们需要读取一个文件,其中包含文本标题,后跟二进制数据的开头.我最初尝试读取此文件是这样的:
private int _dataOffset; void ReadHeader(string path) { using (FileStream stream = File.OpenRead(path)) { StreamReader textReader = new StreamReader(stream); do { string line = textReader.ReadLine(); handleHeaderLine(line); } while(line != "DATA") // Yes,they used "DATA" to mark the end of the header _dataOffset = stream.Position; } } private byte[] ReadDataFrame(string path,int frameNum) { using (FileStream stream = File.OpenRead(path)) { stream.Seek(_dataOffset + frameNum * cbFrame,SeekOrigin.Begin); byte[] data = new byte[cbFrame]; stream.Read(data,cbFrame); return data; } return null; }
问题是,当我将_dataOffset设置为stream.Position时,我得到StreamReader已读取的位置,而不是标头的末尾.一旦我想到它这是有道理的,但我仍然需要能够知道标题的结尾在哪里,我不确定是否有办法做到这一点并仍然利用StreamReader.
解决方法
>获取textReader.CurrentEncoding.GetByteCount(totalLengthOfAllTextRead)的结果,然后在流中寻找此位置.
>使用一些反射hackery来检索StreamReader对象的私有变量的值,该变量对应于内部缓冲区中的当前字节位置(与流不同 – 通常在后面,但当然不超过等于).通过.NET Reflector判断,这个变量似乎被命名为bytePos.
>根本不需要使用StreamReader,而是实现构建在Stream或BinaryReader之上的自定义ReadLine函数(保证BinaryReader永远不会比你要求的更早阅读).这个自定义函数必须通过char读取流char,所以你实际上必须使用低级Decoder对象(除非编码是ASCII / ANSI,在这种情况下,由于单字节编码,事情有点简单) .
选项1将是我想象中效率最低的(因为你有效地重新编码刚解码的文本),而选项3最难实现,尽管可能是最优雅的.我可能建议不要使用丑陋的反射黑客(选项2),即使它看起来很诱人,是最直接的解决方案,只需要几行. (说实话,StreamReader类实际上应该通过公共属性公开这个变量,但是它没有.)所以最后,它取决于你,但是方法1或3应该能够很好地完成工作. ..
希望有所帮助.