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

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

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

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

谢谢你的提示,

安德烈亚斯

试试StAX API( 教程 )。 对于大型文本元素,您应该获得几个文本事件,您需要将它们推送到流式Base64实现(就像提到的一个skaffman)。

Apache Commons Codec有一个Base64OutputStream ,它允许您通过使用FileOutputStream链接Base64OutputStream以可伸缩的方式提供XML数据。

您需要将XML表示为String,因此您甚至可能根本不必将其读入DOM结构。

就像是:

 PrintWriter printWriter = new PrintWriter( new Base64OutputStream( new BufferedOutputStream( new FileOutputStream("/path/to/my/file") ) ) ); printWriter.write(myXml); printWriter.close(); 

如果输入的XML文件太大,那么您应该将它的块读取到循环中的缓冲区中,将缓冲区内容写入输出(即标准的读取器到写入器副本)。

我认为任何XML api都不允许您将元素的文本作为流而不是String访问。 如果String是100 MB,那么您唯一的选择可能是更改JVM的堆大小,直到您没有任何OutOfMemoryError:

 java -Xmx256m your.class.Name 

如果您的文件可以变大,请不要使用DOM解析器。 使用简单的SAX方法访问数据元素,并将base64数据流式传输到Base64OutputStream ,如上所述。

正如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); }