为何检测无BOM的UTF-8文件有效,带BOM的检测却失效?
UTF-8 BOM检测代码行为差异的技术原因
我有一个读取UTF-8文本文件的阅读器,部分文件不含字节顺序标记(BOM)。第一段代码能正确检测BOM:
var utf8NoBom = new UTF8Encoding(false); aReaderWithAFile = new StreamReader(fileName, utf8NoBom) aReaderWithAFile.Read() if (Equals(aReaderWithAFile.CurrentEncoding, utf8NoBom)) { Console.WriteLine("No BOM detected") } else { Console.WriteLine("BOM detected"); }
但第二段代码无论文件是否含BOM,都会显示“BOM detected”:
var utf8WithBom = new UTF8Encoding(true); aReaderWithAFile = new StreamReader(fileName, utf8WithBom) aReaderWithAFile.Read() if (Equals(aReaderWithAFile.CurrentEncoding, utf8WithBom)) { Console.WriteLine("BOM detected"); } else { Console.WriteLine("No BOM detected"); }
我已通过第一段代码解决检测问题,现仅想理解该行为的技术原因:为何第二段代码中Equals会始终返回true?
技术原因解析
这本质是.NET中StreamReader对传入的UTF8Encoding实例的处理逻辑差异:
UTF8Encoding的相等判定规则UTF8Encoding的Equals方法会对比两个实例的EncoderShouldEmitUTF8Identifier属性(也就是构造时传入的布尔值,控制是否生成/识别BOM),属性相同则判定相等。传入
UTF8Encoding(true)时的处理
当你把带BOM标识的UTF8Encoding实例传给StreamReader:
- 如果文件存在BOM:
StreamReader直接使用你传入的实例作为CurrentEncoding,Equals自然返回true。 - 如果文件没有BOM:
StreamReader不会替换编码实例——因为你明确指定了要使用带BOM的UTF-8编码,它默认认为你就是要用这个编码读取文件,哪怕文件本身没带BOM,所以CurrentEncoding还是你传入的那个实例,Equals依然返回true。
- 传入
UTF8Encoding(false)时的处理
而当你传入不带BOM标识的UTF8Encoding实例:
- 如果文件存在BOM:
StreamReader会检测到BOM,此时会把CurrentEncoding替换成一个内置的UTF8Encoding(true)实例,和你传入的实例对比时Equals返回false。 - 如果文件没有BOM:就保留你传入的
UTF8Encoding(false)实例,Equals返回true。
总结来说:StreamReader在你指定带BOM的UTF-8编码时,无论文件有没有BOM都会保留你传入的实例;但指定不带BOM的编码时,遇到BOM会自动替换编码实例,这才导致了两段代码的行为差异。
内容的提问来源于stack exchange,提问作者Toralf Schneider
相关产品推荐
相关产品推荐

