2

我正在尝试在 java 中解析一个最大为 500 mb 的 XML 文件。我尝试使用 SAX,但它给了我这个错误 java.lang.OutOfMemoryError: Java heap space at com.sun.org.apache.xerces.internal.util.XMLStringBuffer.append(Unknown Source) 你能帮帮我吗?非常感谢。PS 较小的 XML 文件可以正常工作

4

7 回答 7

12

很可能您没有正确使用 SAX,或者您的应用程序不适合流处理。

SAX 的重点是避免将整个 XML 结构保存在内存中,但这只有在您可以在不保留太多上下文的情况下以小块处理 XML 并且处理的结果比处理后的 XML 小得多的情况下才有可能(这样它也不会使用太多内存)或者本身可以传递给接收者或连续写入磁盘。

编辑:您也有可能只是发生了内存泄漏,即您持有不再需要的数据,从而阻止它被垃圾收集。如果您使用任何列表、映射或集合来处理 XML,请确保在处理一个 XML 块时添加到它们的任何内容在开始下一个块之前都已删除。

于 2009-02-02T20:40:42.167 回答
5

尝试使用 XML 的 Streaming API(java6 中的新功能)

http://www.javabeat.net/articles/14-java-60-features-part-2-pluggable-annotation-proce-2.html

于 2009-02-02T20:20:45.063 回答
3

您可以尝试通过指定例如来增加 Java 堆大小

java -Xmx1024M MyClass

在命令行上(或任何适合您文档大小的值)。

于 2009-02-02T20:21:30.613 回答
2

StAX for Java 6 之前的版本:http: //stax.codehaus.org/

于 2009-02-02T20:57:49.993 回答
1

假设您有以下 XML 结构:

<?xml version="1.0"?>
<list>
    <item>
        <name>Alpha</name>
        <age>10</age>
    </item>
    <item>
        <name>Beta</name>
        <age>20</age>
    </item>
    <!-- many many items -->
</list>

你想得到所有的 <item>

public class Item
{
    String name;
    String age;
}

您的 SAX 处理程序将如下所示

public class MyHandler extends DefaultHandler
{
    Item current=null;
    StringBuilder content=null;
    
    @Override
    public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException 
    {
        if(name.equals("item"))
        {
            current= new Item();
        }
        else if(name.equals("name") || name.equals("age"))
        {
            content= new StringBuilder();
        }
    }

    @Override
    public void endElement(String uri, String localName, String name) throws SAXException
    {
        if(name.equals("item"))
        {
        //DO SOMETHING WITH current
        System.out.println(current);
        current=null;
        }
        else if(name.equals("name"))
        {
        current.name= content.toString();
        }
        else if(name.equals("age"))
        {
        current.age= content.toString();
        }
        content=null;
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException 
    {
        if(content!=null)
        {
            content.append(ch,start,length);
        }
    }
}

如您所见,content仅在ageandname标记之间被记忆。

于 2009-02-02T21:12:41.680 回答
1

您可能想查看 ScaleDOM,它允许解析非常大的 XML 文件:https ://github.com/whummer/scaleDOM

由于 XML 节点的延迟加载,ScaleDOM 占用的内存很小。它只将 XML 文档的一部分保存在内存中,并在必要时从源文件中重新加载节点。

于 2014-08-26T21:09:28.627 回答
0

看看 Apache Digester。

这是一个小教程

于 2009-05-03T21:30:12.147 回答