我的XML文件(用UTF-8编码)有两个问题:
-
其中一些(不是全部)包含字节顺序标记EF BB BF
-
其中一些(不是全部)包含Null字符00,分布在整个文件中。
这两个问题都使我无法使用SAX解析器解析XML。我目前的方法是将文件读入字符串,并使用regex来提取这些字符并将字符串写回文件,这很好。然而,我的文件相当大(数百兆字节),每次调用replaceAll()时,将文件读入字符串并创建相同大小的结果字符串,很快导致java堆空间错误。
增加堆大小绝对不是一个长期的解决方案。我需要流式传输文件并动态提取所有这些字符。
关于一个有效的解决方案应该是什么样的,有什么建议吗?我会将FilterInputStream
子类化,以便在运行时过滤掉不需要的字节。
这个任务应该是相当容易的,因为字节顺序标记可能只在文件的开头(所以你只需要检查那里),空字节可以很容易地通过一个简单的==
比较来过滤(不需要类似regex的功能)。
这很可能还会提高性能,因为您不需要在重新读取文件之前将完整的更正文件写入磁盘。
为什么不在将数据读入SAX解析器时过滤它呢?这样就不需要重写文件了。您可以覆盖FilterInputStream的read()方法来删除不需要的字节。
我想这就是@Joachim的意思。div;)
我只关注BOM,看到null字节的问题太晚了。我仍然张贴它作为一个额外的情况下,有人有bom只有问题。请尊重反对意见。:)
您可以使用支持mark()
和reset()
的InputStream
读取前三个字节,如果不是BOM则读取前三个字节并复位:
InputStream in = new BufferedInputStream(
new FileInputStream(new File("xmlfile.xml")));
in.mark(3);
byte[] maybeBom = new byte[] {
(byte) in.read(), (byte) in.read(), (byte) in.read() };
if(!Arrays.equals(maybeBom, new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF })) {
in.reset();
}
我用BufferedInputStream
因为FileInputStream
不支持mark()