【问题标题】:decode large base64 from xml in java: OutOfMemory从 java 中的 xml 解码大型 base64:OutOfMemory
【发布时间】:2011-04-29 12:39:47
【问题描述】:

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

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

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

感谢您的提示,

安德烈亚斯

【问题讨论】:

  • 如果文件只能达到 100MB,那么您当然可以将其放入几乎现代桌面的 RAM 中。将 -Xmx500m 传递给 JVM 就可以了。
  • 增加堆大小?还是你在一台 128mb 内存的机器上?

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


【解决方案1】:

Apache Commons Codec 有一个Base64OutputStream,它应该允许您通过将Base64OutputStreamFileOutputStream 链接来以可扩展的方式提供 XML 数据。

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

类似:

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

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

【讨论】:

  • 这将编码为 Base64,不解码。
【解决方案2】:

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

java -Xmx256m your.class.Name

【讨论】:

【解决方案3】:

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

【讨论】:

  • 感谢您的所有帖子,所有提示都做到了。与此同时,我实施了 StAX。但是,我还必须更换旧版本的 commons-codec 才能获得 Base64OutputStream。
【解决方案4】:

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

【讨论】:

    【解决方案5】:

    正如lbruder 所说,使用 SAX 解析器以流方式读取文档。如果你使用Base64OutputStream,那么你必须设置标志让它解码而不是默认的编码。您还必须将字符数组从字符回调转换为字节数组,然后再将其传递给输出流,这需要额外的内存分配和副本。

    我为这个用例编写了一个替代的 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);
    }
    

    【讨论】:

    • 感谢 Jörn,提供此链接。由于我已经在使用 commons-codec,我很高兴继续使用它。不过,我相信其他人可能会发现您的图书馆非常有帮助。
    猜你喜欢
    • 2012-10-04
    • 1970-01-01
    • 2022-01-10
    • 2016-07-25
    • 2010-12-18
    • 1970-01-01
    • 2013-05-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多