问题描述
|
我有一个Java程序,它向我没有修改能力的Web服务发出请求。如果我尝试将其解析为Document对象,则其中一个请求的响应可能会非常大,以至堆耗尽了内存。为了解决这个问题,我将响应逐块读取到byte []缓冲区中,并将其写入磁盘。然后,我计划逐行扫描文件,并从找到的每个元素中构建Document对象(这些是响应中唯一需要的元素):
StringBuilder sb = null;
String line = null;
while( (line = reader.readLine()) != null ){
if(line.trim().equals(\"<bond>\")){
sb = new StringBuilder(line);
}
else if(line.trim().equals(\"</bond>\")){
Document doc = builder.parse(sb.toString());
// Process doc
}
else{
sb.append(line);
}
}
不幸的是,似乎换行符在响应中转换为空格,因此所有内容都是一条巨大的行。我正在考虑的一种解决方案是使用SAX进行解析,并以相同的方式构建我的Document片段。有人有其他解决方案吗?还是我最好的选择?
谢谢,
杰瑞德
解决方法
如果您想使用SAX或DOM解析器,则SAX解析器可能是您最好的选择。它不将xml存储在内存中,因此它将能够处理较大的XML文件。
, 有多种用于在Java中解析XML文档的API。您似乎正在使用DOM API。它读取整个XML文档并将其转换为节点树。您将获得一个包含所有这些节点的“ 1”对象。 DOM API的优点是它相当容易使用,但是缺点是,如您所注意到的,如果XML很大,所有这些节点都将占用大量内存。
还有SAX API,它们的工作方式有所不同。这通过回调机制起作用:您告诉XML解析器,只要它在XML文件中遇到开始或结束标记或数据时就被调用。然后,您可以在回调方法中确定要执行的操作,并且仅存储所需的数据。这样做的好处是可以扩展到大型文档,因为整个XML树不需要驻留在内存中。缺点是该API级别较低,使用起来比较麻烦。
还有StAX,其目的是介于DOM和SAX API之间。
如果您需要处理大型XML文档,则最好使用SAX或StAX API而不是DOM API。
, 如果响应很大,是的,SAX解析器将是合适的,否则创建DOM结构时,您将再次耗尽内存。
我还可以推荐Smooks框架,用于将XML转换为其他形式。它非常适合处理非常大的数据集,并且在(http://www.smooks.org)中内置了许多东西。 Smooks允许您指定XML结构的哪些部分用于生成新的Java对象,XML或其他东西。
, 我认为使用SAXBuilder和XPath可能比while循环更好。
这些线上的东西-
Document doc = new SAXBuilder().build(new StringReader(xmlStr));
XPath xPath = XPath.newInstance(\"/*/YourElement\");
Element ele = xPath.selectSingleNode(doc);
ele.getChild(\"ChildElement\");
, 您可以看一下诸如Nux之类的库,该库使您可以将XML流与XPath结合起来以仅提取所需的值。可能值得研究而不是尝试编写自定义内容。
, 如果堆大小有问题,可以尝试使用以下选项增加堆大小:
java -Xms64m -Xmx256m
这将使您的初始堆大小为64MB,最大为256MB。您可以使用其他值。这样的优点是不需要任何代码更改。