System.IO.File.ReadAllText没有为无效编码引发异常

时间:2017-09-01 18:58:27

标签: .net unicode utf-8 character-encoding

我在文件utf8.txt中有一些UTF-8文本。该文件包含一些超出ASCII范围的字符。我尝试了以下代码:

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中的错误吗?

修改

我最初测试的文件是带有BOM的UTF-8。如果我删除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,虽然胡言乱语。因此,它只是按照您的说明进行操作,并使用您提供的编码对文件进行解码。 (我同意这种行为)

1 个答案:

答案 0 :(得分:1)

  

应抛出异常,因为它不是有效的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手动检查。