【问题标题】:Why is StreamReader and sr.BaseStream.Seek() giving Junk Characters even in UTF8 Encoding为什么 StreamReader 和 sr.BaseStream.Seek() 即使在 UTF8 编码中也会给出垃圾字符
【发布时间】:2020-02-13 07:20:18
【问题描述】:

abc.txt 文件内容为

ABCDEFGHIJ•XYZ

现在,如果我使用此代码(即寻找位置 9),显示的字符就可以了,

            string filePath = "D:\\abc.txt";
            FileStream fs = new FileStream(filePath, FileMode.Open);
            StreamReader sr = new StreamReader(fs, new UTF8Encoding(true), true);
            sr.BaseStream.Seek(9, SeekOrigin.Begin);
            char[] oneChar = new char[1];
            char ch = (char)sr.Read(oneChar, 0, 1);
            MessageBox.Show(oneChar[0].ToString());

但如果 SEEK 位置正好在那个特殊点字符之后,那么我会得到垃圾字符。

所以,如果我搜索到第 11 位(即在点位置之后),我会得到垃圾字符

sr.BaseStream.Seek(11, SeekOrigin.Begin);

这应该给出“X”,因为第 11 位的字符是 X。

我认为文件内容是合法的 UTF8。

还有一件事, StreamReader BaseStream 长度和 StreamReader Contents Length 不同。

   MessageBox.Show(sr.BaseStream.Length.ToString());
   MessageBox.Show(sr.ReadToEnd().Length.ToString());

【问题讨论】:

  • 如果你使用StreamReader,你应该从不寻找底层流;读者假设 it 现在控制流,因为它维护一个内部缓冲区;寻找底层流可能会导致非常奇怪的效果;另外,Seek(9...) 没有任何意义:除非您使用单字节编码,否则您无法通过在 bytes 中查找来查找 9 个 characters,其中:您不是;您需要让StreamReader 丢弃 9 个字符

标签: c# utf-8 streamreader


【解决方案1】:

为什么 StreamReader 和 sr.BaseStream.Seek() 即使在 UTF8 编码中也会给出垃圾字符

正是因为sr.BaseStream UTF-8 提供了垃圾字符。 :)

StreamReader 是一个相对“聪明”的流。它了解 strings 是如何工作的,而 FileStream(即sr.BaseStream)不了解。 FileStream 只知道字节。

由于您的文件以 UTF-8(一种可变长度编码)编码,因此 ABC 等字母使用 1 个字节进行编码,但 字符需要 3 个字节。您可以通过以下方式获取一个字符需要多少字节:

Console.WriteLine(Encoding.UTF8.GetByteCount("•"));

因此,当您将流移动到“紧随 之后的位置”时,您实际上并没有移过,您只是在它的第二个字节上。

Lengths 不同的原因是相似的:StreamReader 给出了字符数,而sr.BaseStream 给出了字节数 .

【讨论】:

  • 那么使用 UTF8 以外的其他编码(如 ascii)是否比 UTF8 更好,以便所有字符(甚至特殊字符)都被视为单字节。因为我想要一个字符到一个字符的平滑搜索,而且几乎不可能考虑到文本文件中每个字符的字节数。但我更喜欢使用 UTF8,因为我也会加密文本文件。
  • @BeeGees 但是,如果您使用 ASCII,您没有可以编码的广泛字符。 UTF-32,它是一种固定宽度的编码,是另一种选择。
  • @BeeGees 看看this extension method。您可能可以使用它来找到要寻找的位置(尽管速度不快)?
  • 我尝试使用 UTF32。它不会给出正常的 A、B 等字符。这是因为默认情况下,没有 BOM 的文本文件被认为是 UTF8
  • @BeeGees 使用 UTF-32,您必须一次读取 4 个字节,并使用 Encoding.UTF32.GetChars 来获取字符。您不能只将结果从 Read 转换为 char
猜你喜欢
  • 2021-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-17
  • 1970-01-01
  • 2021-08-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多