为什么org.apache.xerces.parsers.SAXParser在解析UTF8编码的XML时不能跳过BOM?

7
我有一个使用UTF8编码的XML文件,并且该文件在开头包含BOM字节。因此,在解析时,我遇到了org.xml.sax.SAXParseException: Content is not allowed in prolog的错误。
但我不能从文件中移除这三个字节。由于文件太大,也不能将其加载到内存中并在此处删除。
为了提高性能,我使用SAX解析器,如果在""标记之前存在这3个字节,则仅跳过它们。 那么我应该继承InputStreamReader来实现吗?
由于我对Java还不熟悉,请指导正确的做法。

3个回答

4
这个问题以前就出现过,当我遇到它时,我在Stack Overflow上找到了答案。链接的答案使用PushbackInputStream来测试BOM。请参考:the answer

3

我曾经遇到过同样的问题,我用这段代码解决了它:

private static InputStream checkForUtf8BOM(InputStream inputStream) throws IOException {
    PushbackInputStream pushbackInputStream = new PushbackInputStream(new BufferedInputStream(inputStream), 3);
    byte[] bom = new byte[3];
    if (pushbackInputStream.read(bom) != -1) {
        if (!(bom[0] == (byte) 0xEF && bom[1] == (byte) 0xBB && bom[2] == (byte) 0xBF)) {
            pushbackInputStream.unread(bom);
        }
    }
    return pushbackInputStream;
}

这是针对UTF8的...我认为UTF16会有所不同(我相信它只有2个字节)? - Trinition
抱歉回复晚了。是的,UTF16带有BOM,只有两个字节:0xFE 0xFF(大端)或0xFF 0xFE(小端)。 - javanna

2
private static char[] UTF32BE = { 0x0000, 0xFEFF };
private static char[] UTF32LE = { 0xFFFE, 0x0000 };
private static char[] UTF16BE = { 0xFEFF };
private static char[] UTF16LE = { 0xFFFE };
private static char[] UTF8 = { 0xEFBB, 0xBF };

private static boolean removeBOM(Reader reader, char[] bom) throws Exception {
    int bomLength = bom.length;
    reader.mark(bomLength);
    char[] possibleBOM = new char[bomLength];
    reader.read(possibleBOM);
    for (int x = 0; x < bomLength; x++) {
        if ((int) bom[x] != (int) possibleBOM[x]) {
            reader.reset();
            return false;
        }
    }
    return true;
}

private static void removeBOM(Reader reader) throws Exception {
    if (removeBOM(reader, UTF32BE)) {
        return;
    }
    if (removeBOM(reader, UTF32LE)) {
        return;
    }
    if (removeBOM(reader, UTF16BE)) {
        return;
    }
    if (removeBOM(reader, UTF16LE)) {
        return;
    }
    if (removeBOM(reader, UTF8)) {
        return;
    }
}

使用方法:

// xml can be read from a file, url or string through a stream
URL url = new URL("some xml url");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(url.openStream()));
removeBOM(bufferedReader);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接