【问题标题】:How to Remove BOM from an XML file in Java如何从 Java 中的 XML 文件中删除 BOM
【发布时间】:2012-04-01 23:31:43
【问题描述】:

我需要有关如何从 UTF-8 文件中删除 BOM 并创建 xml 文件其余部分的副本的建议。

【问题讨论】:

  • 否决票不是因为重复,而是因为这个问题本质上太宽泛了——stackoverflow 是为了帮助解决特定的本地化编程问题。我们可以帮助您调试程序,我们不会为您编写。
  • 我在等到 -5 再回答; )
  • @hari: 你文件的编码是什么? UTF-8 ?
  • 我不是在要求人们为我编写代码...我是在寻求有关如何编写代码的建议。我想知道这是否可能。人们会盲目投票。
  • @TacticalCoder 是的。它带有 Bom 的 Utf-8。如果它的 Utf-8 没有 Bom,我使用的解析器可以工作。

标签: java utf-8 byte-order-mark


【解决方案1】:

根据我的经验,由于 UTF-8 文件中的 BOM 而导致工具损坏是非常常见的事情。我不知道为什么会有如此多的反对票(但它让我有机会尝试获得足够的选票来赢得特殊的 SO 徽章;)

更严重的是:UTF-8 BOM 通常没有那么大的意义它在规范中是完全有效的(尽管不鼓励)。现在的问题是,很多人不知道 BOM 在 UTF-8 中有效,因此编写了无法正确处理这些文件的损坏工具/API。

现在您可能有两个不同的问题:您可能想要从 Java 处理文件,或者您需要使用 Java 以编程方式创建/修复其他(损坏的)工具需要的文件。

我曾在一次咨询工作中遇到过这样的案例,在该案例中,服务台会不断收到来自用户的消息,这些用户对某些文本编辑器有问题,这些文本编辑器会弄乱由 Java 生成的完全有效的 UTF-8 文件。所以我必须通过确保从我们正在处理的每个 UTF-8 文件中删除 BOM 来解决这个问题。

如果您想从文件中删除 BOM,您可以创建一个新文件并跳过前三个字节。例如:

... $  file  /tmp/src.txt 
/tmp/src.txt: UTF-8 Unicode (with BOM) English text

... $  ls -l  /tmp/src.txt 
-rw-rw-r-- 1 tact tact 1733 2012-03-16 14:29 /tmp/src.txt

... $  hexdump  -C  /tmp/src.txt | head -n 1
00000000  ef bb bf 50 6f 6b 65 ...

如您所见,文件以“ef bb bf”开头,这是(完全有效的)UTF-8 BOM。

这是一个获取文件并通过跳过前三个字节来复制它的方法:

 public static void workAroundbrokenToolsAndAPIs(File sourceFile, File destFile) throws IOException {
    if(!destFile.exists()) {
        destFile.createNewFile();
    }

    FileChannel source = null;
    FileChannel destination = null;

    try {
        source = new FileInputStream(sourceFile).getChannel();
        source.position(3);
        destination = new FileOutputStream(destFile).getChannel();
        destination.transferFrom( source, 0, source.size() - 3 );
    }
    finally {
        if(source != null) {
            source.close();
        }
        if(destination != null) {
            destination.close();
        }
    }
}

请注意,它是“原始的”:您通常需要先确保您有一个 BOM,然后再调用它或“Bad Thinks May Happen”[TM]。

之后您可以查看您的文件:

... $  file  /tmp/dst.txt 
/tmp/dst.txt: UTF-8 Unicode English text

... $  ls -l  /tmp/dst.txt 
-rw-rw-r-- 1 tact tact 1730 2012-03-16 14:41 /tmp/dst.txt

... $  hexdump -C /tmp/dst.txt
00000000  50 6f 6b 65 ...

BOM 不见了……

现在,如果您只是想透明地删除损坏的 Java API 的 BOM,那么您可以使用此处描述的 pushbackInputStreamwhy org.apache.xerces.parsers.SAXParser does not skip BOM in utf8 encoded xml?

private static InputStream checkForUtf8BOMAndDiscardIfAny(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; }

请注意,这可行,但绝对可以解决更严重的问题,即工作链中的其他工具无法正确处理具有 BOM 的 UTF-8 文件。

这里有一个问题的链接,该问题的答案更完整,也涵盖了其他编码:

Byte order mark screws up file reading in Java

【讨论】:

  • 投票不是对问题主题的判断,而是对问题质量的判断。查看投票按钮的工具提示。
  • @skaffman:好的,但我没有投票反对,而是询问 OP 是否使用 UTF-8 文件(我怀疑该问题太常见了),然后将其添加到问题中(并编辑了标签)。我不知道还能说什么:“如何从文件中删除 BOM?” 非常不言自明。我添加了“UTF-8”。当然,对我来说,简单地投反对票会更容易; )
  • @TacticalCoder 非常感谢您的建议。我相信这会解决我的问题。
  • @TacticalCoder 解决了我遇到的问题!我也可以知道如果我从文件中删除 Bom 是否会有任何问题...还有其他依赖于 bom 吗?
  • 感谢最后的小功能 sn-p。不是一个java人,不知道推回。比导入 apache commons 麻烦得多。一般来说,如果你写了一个很长的问题,那么它就不会被否决。如果他已经谈论了该程序的所有内容,它的投入,等等等等,那会很好。语义相同,但被接受。 :)
猜你喜欢
  • 1970-01-01
  • 2010-09-22
  • 1970-01-01
  • 2017-12-27
  • 2014-02-07
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多