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

在java:OutOfMemory中从xml解码大型base64,java,xml,file-io,base64,out-of-memory,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

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

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

有没有一种方法可以将这个base64编码的部分流式传输到一个文件中,而不用在一个单独的片段中获取整个块

谢谢你的提示

Andreas

有一个,它应该允许您通过将
Base64OutputStream
FileOutputStream
链接,以可伸缩的方式提供XML数据

您需要将XML表示为字符串,这样您甚至不必将其读入DOM结构

比如:

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

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

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

java -Xmx256m your.class.Name

如果你的文件有那么大,千万不要使用DOM解析器。使用简单的SAX方法访问数据元素,并如上所述将base64数据流式传输到
Base64OutputStream

尝试使用StAX API()。对于大型文本元素,您应该获得几个文本事件,需要将这些事件推送到streaming Base64实现中(如skaffman所述)。

如前所述,使用SAX解析器以流式方式读取文档。如果使用,则必须设置标志以使其解码,而不是默认编码。在将字符数组传递到outputstream之前,还必须将字符数组从characters回调转换为字节数组,这需要额外的内存分配和拷贝

我为这个用例编写了另一个base64解码器,它可以在。下面是一个关于如何使用它的示例:

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

如果该文件只能达到100MB,那么您当然可以将其安装在几乎现代化的桌面上的RAM中。将
-Xmx500m
传递给JVM就可以了。增加堆大小?或者你是在一台有128mb内存的机器上?谢谢你的所有帖子,所有的提示都做到了。同时,我还实施了StAX。不过,我还必须更换旧版本的commons编解码器才能获得Base64OutputStream。感谢Jörn提供此链接。由于我已经在使用commons编解码器,我很高兴继续使用它。不过,我相信其他人可能会觉得你的库非常有用。这似乎是不正确的。请参阅我的问题(和答案)。