【问题标题】:System.IO.File.ReadAllText not throwing exception for invalid encodingSystem.IO.File.ReadAllText 不为无效编码抛出异常
【发布时间】:2018-02-10 21:16:09
【问题描述】:

我在文件 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 字符串(该字符串在调试器中 not 看起来是正确的)。

编辑:

要生成我的测试文件,请运行以下代码:

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,虽然是胡言乱语。所以它只是按照你的指示,用你给它的编码解码文件。 (我同意这种行为)

【问题讨论】:

  • 您能否提供文件中您认为有问题的文本示例?
  • 我想到了,但最好的方法是什么?我真的很想发布一个二进制文件。
  • 可能只是您期望失败的几个字符编码,我们可以根据它重新创建文本吗?或者,也许我可以出去找到一些晦涩的 utf8 文本并使用它。我认为它不是特定字符,只是您担心的任何无效 ISO-8859-1 字符
  • ISO-8859-1 是 8 位编码,所以我相信 0x00 到 0xFF 的字符是允许的。
  • "因为大多数(全部?)UTF-8 文本也是有效的 ISO-8859-1" - 这仅适用于 ASCII 字节 0x20-0x7E,它们是相同的在 UTF-8 和 ISO-8859-1 中。一旦超出该范围,UTF-8 就不是有效的 ISO-8859-1。字节 0x00-0x1F 和 0x7F-0x9F 在 ISO-8859-1 中未定义(0x00 值得商榷,因为它通常用作空终止符),以及 UTF-8 中的大多数非 ASCII 字节由于 UTF-8 对其位的编码方式,属于后者。

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


【解决方案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 手动检查。

【讨论】:

    猜你喜欢
    • 2013-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-28
    • 2016-11-07
    • 1970-01-01
    • 1970-01-01
    • 2013-11-29
    相关资源
    最近更新 更多