System.IO.File.ReadAllText不会引发无效编码的异常

问题描述:

我在文件utf8.txt中有一些UTF-8文本。该文件包含一些在ASCII范围之外的字符。我尝试下面的代码:System.IO.File.ReadAllText不会引发无效编码的异常

var fname = "utf8.txt"; 
var enc = Encoding.GetEncoding("ISO-8859-1", EncoderFallback.ExceptionFallback, 
    DecoderFallback.ExceptionFallback); 
var s = System.IO.File.ReadAllText(fname, enc); 

预期的行为是代码应该抛出一个异常,因为它不是有效的ISO-8859-1文本。相反,其行为是将UTF-8文本正确解码为正确的字符(它在调试器中看起来正确)。

这是一个错误.Net

编辑:

我原来测试的文件是UTF-8 BOM。如果我删除BOM,行为会改变。它仍然不会引发异常,但它会产生不正确的Unicode字符串(在调试器中字符串不是看起来是正确的)。

编辑:

为了生产我的测试文件,运行下面的代码:

var fname = "utf8.txt"; 
var utf8_bom_e_circumflex_bytes = new byte[] {0xEF, 0xBB, 0xBF, 0xC3, 0xAA}; 
System.IO.File.WriteAllBytes(fname, utf8_bom_e_circumflex_bytes); 

编辑:

我想我有是怎么回事坚定的手柄(尽管我不同意.Net的一部分行为)。

  • 如果文件开始使用UTF-8 BOM,数据是有效的UTF-8,然后ReadAllText会完全忽略你在通过编码和(正确)解码文件为UTF-8。 (我还没有测试过,如果BOM是一个谎言,文件不是真的UTF-8会发生什么)我不同意这种行为。我认为.Net应该抛出一个异常或使用我给它的编码。

  • 如果文件没有BOM,那么.Net并没有微不足道(和100%可靠)的方式来确定文本不是真的ISO-8859-1,因为大多数(所有?)UTF-8文本也是有效的ISO-8859-1,尽管乱七八糟。所以它只是遵循你的指示,并用你给它的编码解码文件。 (我也有这种行为同意)

+0

您能否提供您希望存在问题的文件中的文本示例? – DontThinkJustGo

+0

我想到了这一点,但是最好的办法是什么?我真的想发布一个二进制文件。 – JoelFan

+0

也许只是一对字符编码,你会希望失败,我们可以重新创建文本的基础上呢?或者,也许我可以出去找一些模糊的utf8文本并使用它。我认为它不是一个特定的字符,只是您关心的任何无效的ISO-8859-1字符 – DontThinkJustGo

应该抛出一个异常,因为它不是有效的ISO-8859-1文本

在ISO-8859-1的所有可能的字节都映射到字符,因此读取ISO-8859-1以外的ISO-8859-1文件不会导致异常。 (真的,0x80-0x9F范围内的所有字节都将成为你永远不想要的无形控制码,但它们仍然有效,只是无用而已。很多ISO-8859编码都是如此,它将C1控制代码放在0x80-0x9F范围内,但不是全部。你可以肯定会得到一个例外,其他编码会导致字节未映射,例如Windows-1252。)

如果文件以UTF-8 BOM开始,并且数据是有效的UTF-8,那么ReadAllText将完全忽略您传入的编码并(正确)将文件解码为UTF-8。

是的。这在文档暗示:

This method attempts to automatically detect the encoding of a file based on the presence of byte order marks. 

我同意你,这种行为是非常愚蠢的。我宁愿ReadAllBytes并手动检查它通过Encoding.GetString