c# - 在同一个 Stream 上创建多个 StreamReader 的奇怪行为
问题描述
我正在使用有限状态机来读取一个超大文件。它不是多线程的,所以不会有线程安全的问题。
它包含3种内容:
- 二进制数,表示后面字符串的长度,一个字符计为1
- ANSI,一个字符占用 1~2 个字节
- UTF-8,一个字符占用 1~4 个字节
我发现这个问题可能有用,但它失败了。类似的python 问题也没有用,因为它不会抛出任何错误。我必须以正确的编码阅读内容,否则行为将变得未知。
目前,我正在使用StreamReader,但是一旦 StreamReader 初始化,就无法更改CurrentEncoding属性。
所以我也尝试在同一个Stream上重新创建 StreamReader :
reader = new StreamReader(stream, encoding65001); //UTF-8
DoSomething(reader);
reader = new StreamReader(stream, encoding1252); //ANSI
DoSomething(reader);
reader = new StreamReader(stream, encoding936); //ANSI
//...
但它开始从一个未知的位置读取奇怪的内容。我还没有找出这种奇怪行为的可能原因。
我是否在创建多个StreamReader时犯了错误,或者它被设计为不在同一个流上创建多个?
如果是这样设计的,是否有读取此类文件的解决方案?
感谢您花时间阅读。
编辑: 我在 .NET Core 3.1 上运行了以下代码:
Stream stream = File.OpenRead(testFilePath);
Console.WriteLine(stream.Position);
Console.WriteLine(stream.ReadByte());
Console.WriteLine(stream.Position + "\r\n");
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
Console.WriteLine(reader.Read());
Console.WriteLine(stream.Position + "\r\n");
reader = new StreamReader(stream, CodePagesEncodingProvider.Instance.GetEncoding(1252));
Console.WriteLine(reader.Read());
Console.WriteLine(stream.Position);
使用以下示例文本:
abcdefg
和输出:
0
97
1
98
7
-1
7
这很奇怪也很有趣。
解决方案
流阅读器将从他们正在阅读的底层流中缓冲内容,这就是导致您出现问题的原因。仅仅因为您从阅读器中读取了一个字符,并不意味着它只会从底层流中读取一个字符。它会用字节填充一段时间缓冲区,然后从缓冲区中产生一个字符。
如果您想从流中读取值并将不同的字节部分解释为不同的编码(为了记录,如果可能的话,您应该避免将自己置于数据中混合编码的位置),您将不得不拉自己从流中取出字节,然后使用适当的编码转换字节,这样您就可以确保只提取您想要的字节的确切部分,而不是更多。
推荐阅读
- r - 如何根据excel csv中的关键字过滤R中的表格?
- django - 使用 git 管理 sqlite 数据库
- android - gradle中的“com.google.android.gms ...”和“com.google.firebase ...”有什么区别?
- c# - Zipfile OpenRead throws Access to the path is denied exception in c# uwp app?
- javascript - HTML 使用 MediaRecorder 记录画布,里面有视频
- c# - Webform 的几个 Dropdownlist 值未存储在数据库中
- grails - grails域类约束中的空白和可为空有什么区别?
- python - 如何在 Mac 上修复 Python 中的“NotADirectoryError”
- postgresql - 为什么在 RHEL 8 / CentOS 8 上安装 PostGIS 3 是不可能的?
- laravel-blade - Laravel Blade 包含在包含中