我需要将xml文件的base64编码元素写入单独的文件中。问题:文件很容易达到100 MB的大小。我尝试的每个解决方案都以“java.lang.OutOfMemoryError:Java堆空间”结束。问题不是一般读取xml或解码过程,而是读取base64块的大小。
我使用jdom,dom4j和XMLStreamReader来访问xml文件。但是,只要我想访问相应元素的base64内容,我就会得到上述错误。我也尝试使用saxon的base64Binary-to-octets函数的xslt,但当然也有相同的结果。
有没有办法将这个base64编码的部分流式传输到一个文件中,而不需要将整个块放在一个块中?
感谢您的提示,
安德烈亚斯
答案 0 :(得分:2)
Apache Commons Codec有一个Base64OutputStream
,它允许您通过将Base64OutputStream
与FileOutputStream
相关联,以可扩展的方式提供XML数据。
您需要将XML表示为String,因此您甚至可能根本不需要将其读入DOM结构。
类似的东西:
PrintWriter printWriter = new PrintWriter(
new Base64OutputStream(
new BufferedOutputStream(
new FileOutputStream("/path/to/my/file")
)
)
);
printWriter.write(myXml);
printWriter.close();
如果输入的XML文件太大,那么你应该将它的块读取到循环中的缓冲区中,将缓冲区内容写入输出(即标准的读写器到写入器副本)。
答案 1 :(得分:1)
我认为任何XML api都不允许您将元素的文本作为流而不是String来访问。如果String是100 MB,那么您唯一的选择可能是更改JVM的堆大小,直到您没有任何OutOfMemoryError:
java -Xmx256m your.class.Name
答案 2 :(得分:0)
如果您的文件可以变大,请不要使用DOM解析器。使用简单的SAX方法访问数据元素,并将base64数据流式传输到Base64OutputStream
,如上所述。
答案 3 :(得分:0)
尝试使用StAX API(tutorial)。对于大型文本元素,您应该获得几个文本事件,您需要将它们推送到流式Base64实现(就像提到的一个skaffman)。
答案 4 :(得分:0)
如lbruder所述,使用SAX解析器以流方式读取文档。如果使用Base64OutputStream,则必须设置标志以使其为DECODE而不是默认的ENCODE。您还必须将char数组从字符回调转换为字节数组,然后再将其传递给输出流,需要额外的内存分配和副本。
我为这个用例编写了一个替代的base64解码器,它可以在github获得。以下是如何使用它的示例:
Base64StreamDecoder decoder = new Base64StreamDecoder();
OutputStream out;
...
public void startElement(String uri, String localName, String qName, Attributes atts) {
decoder.reset();
out = new BufferedOutputStream(new FileOutputStream(...));
}
public void endElement(String uri, String localName, String qName) {
decoder.checkComplete();
out.close();
}
public void characters(char[] ch, int start, int length) {
decoder.decode(ch, start, length, out);
}