我正在寻找一种可靠的方法来将 StreamReader 重置为开始,特别是当他的底层 BaseStream 以 BOM 开头时,但在没有 BOM 时也必须工作。创建一个从流的开头读取的新 StreamReader 也是可以接受的。
可以使用任何编码创建原始 StreamReader,并将 detectEncodingFromByteOrderMarks 设置为 true 或 false。此外,在调用重置之前,可能已经完成或未完成读取。
流可以是随机文本,以字节 0xef,0xbb,0xbf 开头的文件可以是具有 BOM 的文件或以有效字符序列开头的文件(例如,如果使用 ISO-8859-1 编码,则为 ),具体取决于创建 StreamReader 时使用的参数。
我见过其他解决方案,但是当 BaseStream 以 BOM 开头时,它们无法正常工作。StreamReader 记得它已经检测到 BOM,并且执行读取时返回的第一个字符是特殊的 BOM 字符。
我也可以创建一个新的 StreamReader,但我不知道原始 StreamReader 是在 detectEncodingFromByteOrderMarks 设置为 true 还是设置为 false 的情况下创建的。
这是我首先尝试过的:
//fails with TestMethod1
void ResetStream1(ref StreamReader sr) {
sr.BaseStream.Position = 0;
sr.DiscardBufferedData();
}
//fails with TestMethod2
void ResetStream2(ref StreamReader sr) {
sr.BaseStream.Position = 0;
sr = new StreamReader(sr.BaseStream, sr.CurrentEncoding, true);
}
//fails with TestMethod3
void ResetStream3(ref StreamReader sr) {
sr.BaseStream.Position = 0;
sr = new StreamReader(sr.BaseStream, sr.CurrentEncoding, false);
}
这些是最好的方法:
Stream StreamWithBOM = new MemoryStream(new byte[] {0xef,0xbb,0xbf,(byte)'X'});
[TestMethod]
public void TestMethod1() {
StreamReader sr=new StreamReader(StreamWithBOM);
int before=sr.Read(); //reads X
ResetStream(ref sr);
int after=sr.Read();
Assert.AreEqual(before, after);
}
[TestMethod]
public void TestMethod2() {
StreamReader sr = new StreamReader(StreamWithBOM,Encoding.GetEncoding("ISO-8859-1"),false);
int before = sr.Read(); //reads ï
ResetStream(ref sr);
int after = sr.Read();
Assert.AreEqual(before, after);
}
[TestMethod]
public void TestMethod3() {
StreamReader sr = new StreamReader(StreamWithBOM, Encoding.GetEncoding("ISO-8859-1"), true);
int expected = (int)'X'; //no Read() done before reset
ResetStream(ref sr);
int after = sr.Read();
Assert.AreEqual(expected, after);
}
最后,我找到了一个解决方案(见我自己的答案),它通过了所有 3 个测试,但我想看看是否有可能更优雅或更快速的解决方案。