从java中的xml解码大型base64:OutOfMemory

时间:2011-04-29 12:39:47

标签: java xml file-io base64 out-of-memory

我需要将xml文件的base64编码元素写入单独的文件中。问题:文件很容易达到100 MB的大小。我尝试的每个解决方案都以“java.lang.OutOfMemoryError:Java堆空间”结束。问题不是一般读取xml或解码过程,而是读取base64块的大小。

我使用jdom,dom4j和XMLStreamReader来访问xml文件。但是,只要我想访问相应元素的base64内容,我就会得到上述错误。我也尝试使用saxon的base64Binary-to-octets函数的xslt,但当然也有相同的结果。

有没有办法将这个base64编码的部分流式传输到一个文件中,而不需要将整个块放在一个块中?

感谢您的提示,

安德烈亚斯

5 个答案:

答案 0 :(得分:2)

Apache Commons Codec有一个Base64OutputStream,它允许您通过将Base64OutputStreamFileOutputStream相关联,以可扩展的方式提供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);
}