【问题标题】:Encoding detection method doesn't work编码检测方法不起作用
【发布时间】:2013-02-24 03:44:56
【问题描述】:

我需要检查文件的编码类型。如果它是可读的,则返回 true。
根据SO answer,我将此逻辑转换为 Java 代码。但它不起作用。正是,这部分代码:

if ((buffer[0] & 0xF8) == 0xF0) {
        if (((buffer[1] & 0xC0) == 0x80)
            && ((buffer[2] == 0x80) && ((buffer[3] == 0x80))))
            return true;
    } else if ((buffer[0] & 0xF0) == 0xE0) {
        if (((buffer[1] & 0xC0) == 0x80) && ((buffer[2] & 0xC0) == 0x80))
            return true;
    } else if ((buffer[0] & 0xE0) == 0xC0) {
        if (((buffer[1] & 0xC0) == 0x80))
            return true;
    } return false;

这不正确检查,此时正在检查 100% UTF-8 代码! => 结果return false

所有代码:

class EncodindsCheck implements Checker {
    private static final int UTF8_HEADER_SIZE = 8;

    @Override
    public boolean check(File currentFile) {
        return isUTF8(currentFile);
    }

    public static boolean isUTF8(File file) {
        // validate input
        if (null == file) {
            throw new IllegalArgumentException("input file can't be null");
        }
        if (file.isDirectory()) {
            throw new IllegalArgumentException(
                    "input file refers to a directory");
        }

        // read input file
        byte[] buffer;
        try {
            buffer = readUTFHeaderBytes(file);
        } catch (IOException e) {
            throw new IllegalArgumentException(
                    "Can't read input file, error = " + e.getLocalizedMessage());
        }

        if ((buffer[0] & 0xF8) == 0xF0) {
            if (((buffer[1] & 0xC0) == 0x80)
                && ((buffer[2] == 0x80) && ((buffer[3] == 0x80))))
                return true;
        } else if ((buffer[0] & 0xF0) == 0xE0) {
            if (((buffer[1] & 0xC0) == 0x80) && ((buffer[2] & 0xC0) == 0x80))
                return true;
        } else if ((buffer[0] & 0xE0) == 0xC0) {
            if (((buffer[1] & 0xC0) == 0x80))
                return true;
        }

        return false;
    }

    private static byte[] readUTFHeaderBytes(File input) throws IOException {
        byte[] buffer = new byte[UTF8_HEADER_SIZE];
        // read data
        FileInputStream fis = new FileInputStream(input);
        fis.read(buffer);
        fis.close();
        return buffer;
    }
}

问题:

  • 为什么这个检查不起作用?
  • 如何以这种方式解决此检查检测(作为 UTF-8 字符序列)?
  • 如何检查其他字符集(UTF-16 等)?

【问题讨论】:

  • 您能否提供一个失败的 UTF-8 文件示例?
  • @jazzbassrob 我该怎么做?
  • 您是否阅读了原始的 SO 答案?缓冲区 [0] 甚至有一个字节 > 0x7f 吗?
  • @Ingo 你建议如何改变这种方法?
  • 我没有。我只是指出,您链接到的 SO 答案引入了此逻辑,以查看以 byte > 0x7f 开头的字节序列是否形成有效的 UTF8 代码。

标签: java character-encoding decoding


【解决方案1】:

UTF-8 中的代码点长度可以是 1、2、3 或 4 个字节。

如果所有代码点都在 U+0000 到 U+007F 范围内,那么 isUTF8 将返回 false。在这种情况下,该文件将适用于大量编码(UTF-8、ASCII、ANSI 编码等)

您的 UTF-8 检查相信运气好,第一个代码点高于 U+007F。

我建议你看看a more comprehensive encoding detection API,至少作为一个例子。


请注意,fis.read(buffer); 不能保证填充数组;类型协定要求您检查读取的字节数的返回值。

【讨论】:

  • 我该如何解决这个问题,并以有效的方式检查文件?你介意我问,为什么我们应该做(buffer[0] & 0xF8) 和这个结果== 0xF0 - 在这个例子中。为什么我们需要这个变体?
  • fis.read(buffer); - 如何规避这种不确定性?
  • 我还没有检查你的号码,但口罩应该检查the encoding scheme。例如,如果第一个字节匹配1110xxxx,那么接下来的两个必须匹配10xxxxxx。但是,您可以避免所有这些,并使用Decoder 类型到check for malformed input。并不是说这会保证文件是 UTF-8 - 只是数据不违反这些规则 - 没有办法可靠地检测编码。
  • 您关于fis.read(buffer) 的问题需要提出一个新问题。
  • 我们可以为这个目标使用jChardet吗?
猜你喜欢
  • 2017-11-07
  • 1970-01-01
  • 2011-10-24
  • 1970-01-01
  • 2011-10-06
  • 1970-01-01
  • 2013-04-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多