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

Why is StreamReader and sr.BaseStream.Seek() giving Junk Characters even in UTF8 Encoding

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());

Why is StreamReader and sr.BaseStream.Seek() giving Junk Characters even in UTF8 Encoding

正是因为 UTF-8,sr.BaseStream 给出了垃圾字符。 :)

StreamReader是比较"smarter"流。它理解 strings 是如何工作的,而 FileStream(即 sr.BaseStream)则不然。 FileStream 只知道字节。

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

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

因此,当您将流移至 "the position just after " 时,您实际上并没有移过 ,您只是在它的第二个字节上。

Length 不同的原因是相似的:StreamReader 给你 个字符 ,而 sr.BaseStream 给你字节数.