使用StreamReader读取编码标识符



我正在读一本C#书,在关于流的章节中,它说:

如果显式指定编码,StreamWriter将在默认情况下,在流的开头写一个前缀来标识编码。这通常是不可取的,您可以通过构造编码如下:

var encoding = new UTF8Encoding (encoderShouldEmitUTF8Identifier:false, throwOnInvalidBytes:true);

我想看看标识符的外观,所以我想出了这个代码:

using (FileStream fs = File.Create ("test.txt"))
using (TextWriter writer = new StreamWriter (fs,new UTF8Encoding(true,false)))
{
writer.WriteLine ("Line1");
}
using (FileStream fs = File.OpenRead ("test.txt"))
using (TextReader reader = new StreamReader (fs))
{
for (int b; (b = reader.Read()) > -1;)
Console.WriteLine (b + " " + (char)b);  // identifier not printed
}

令我不满的是,没有打印识别码。如何读取标识符?我是不是错过了什么?

默认情况下,.NET会非常努力地将您与编码错误隔离开来。如果你想看到字节顺序标记,也就是"前导码"或"BOM",你需要非常明确地使用对象来禁用自动行为。这意味着您需要使用不包括前导码的编码,您需要告诉StreamReader不要尝试检测编码。

以下是原始代码的变体,将显示BOM:

using (MemoryStream stream = new MemoryStream())
{
Encoding encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true);
using (TextWriter writer = new StreamWriter(stream, encoding, bufferSize: 8192, leaveOpen: true))
{
writer.WriteLine("Line1");
}
stream.Position = 0;
encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
using (TextReader reader = new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks: false))
{
for (int b; (b = reader.Read()) > -1;)
Console.WriteLine(b + " " + (char)b);  // identifier not printed
}
}

这里,encoderShouldEmitUTF8Identifier: true被传递到用于创建流的编码器,从而在创建流时写入BOM,但encoderShouldEmitUTF8Identifier: false被传递到用来读取流的编码器中,从而在读取流时BOM将被视为正常字符。detectEncodingFromByteOrderMarks: false参数也传递给StreamReader构造函数,这样它就不会占用BOM表本身。

这会产生这种输出,就像你想要的那样:

65279?76升105 i110 n101 e49 11310

值得一提的是,通常不鼓励使用BOM作为识别UTF8编码的形式。BOM的存在主要是为了区分UTF16的两种变体(即UTF16LE和UTF16BE,分别为"小端序"one_answers"大端序"(。它也被选为识别UTF8的一种方法,但实际上最好只知道编码是什么(这就是为什么XML和HTML等东西在文件的第一部分明确表示编码为ASCII,并且MIME的charset属性存在(。一个字符并不像其他更明确的方式那样可靠。

最新更新