Java 巨大的XML文件:我是否每次读取一个“页面”并处理它?
我需要处理一个巨大的XML文件,4G。我使用了dom4j SAX,但编写了自己的DefaultElementHandler。代码框架如下:Java 巨大的XML文件:我是否每次读取一个“页面”并处理它?,java,xml,sax,Java,Xml,Sax,我需要处理一个巨大的XML文件,4G。我使用了dom4j SAX,但编写了自己的DefaultElementHandler。代码框架如下: SAXParserFactory sf = SAXParserFactory.newInstance(); SAXParser sax = sf.newSAXParser(); sax.parse("english.xml", new DefaultElementHandler("page"){ public void processEle
SAXParserFactory sf = SAXParserFactory.newInstance();
SAXParser sax = sf.newSAXParser();
sax.parse("english.xml", new DefaultElementHandler("page"){
public void processElement(Element element) {
// process the element
}
});
我以为我在一页一页地处理这个巨大的文件。但似乎不是,因为我总是有内存不足的错误。我错过了什么重要的事情吗?谢谢我不熟悉XML过程 实际上,您并不是按照页面来处理XML,但是如果您扩展了XMLFilterImpl而不是使用DefaultElementHandler,那么您可以简单地处理XML元素。您将进行流式处理,因此在实际操作中不会出现整个文档都在内存中的情况 实际上,您将在元素的开头、属性、元素中的文本中调用事件元素,然后在元素的结尾查看ContentHandler接口中的方法。在处理这些调用的基础上,您可能需要一些数据结构,以便在页面元素中积累元素。还要注意的是,不能保证您只会得到一次文本调用,这取决于解析器
这有助于让它更清晰吗?我认为它只读取元素中的所有内容,因为我刚刚在网上学习了一个示例 公共抽象类DefaultElementHandler扩展了DefaultHandler{ 私有布尔开始; 私有字符串标记名; 私人架线工
public DefaultElementHandler(String tagName) {
this.tagName = tagName;
this.begin = false;
this.sBuilder = new StringBuilder();
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equals(tagName)||begin){
sBuilder.append("<");
sBuilder.append(qName);
sBuilder.append(" ");
int attrCount = attributes.getLength();
for (int i=0; i<attrCount; i++) {
sBuilder.append(attributes.getQName(i));
sBuilder.append("=\"");
sBuilder.append(attributes.getValue(i));
sBuilder.append("\" ");
}
sBuilder.append(">");
begin = true;
}
}
public void characters(char[] ch, int start, int length) throws SAXException{
StringBuilder sb = new StringBuilder();
for(int i=0; i < length; i++) {
sb.append(convertSpecialChar(ch[start+i]));
}
String text = sb.toString().trim();
//String text = new String(convertSpecialChar(ch), start, length);
if (text.trim().equals("")) return;
if (begin) sBuilder.append(text);
}
public void endElement(String uri, String localName, String qName) throws SAXException {
String stag = "</" + tagName + ">";
String ntag = "</" + qName + ">";
if (stag.equals(ntag) || begin) {
sBuilder.append(ntag);
if (stag.equals(ntag)) {
begin = false;
try {
Document doc = DocumentHelper.parseText(sBuilder.toString());
Element element = doc.getRootElement();
this.processElement(element);
} catch (DocumentException e) {
e.printStackTrace();
System.exit(1);
}
sBuilder.setLength(0);
}
}
}
在我看来,您的DefaultElement实现看起来很混乱。它看起来像是sBuilder中的所有内容都在堆积,在找到根元素的结尾之前,它永远不会被清除,或者更可能的是,内存不足 如何读入元素文本取决于需要解析的xml类型。每个元素可以有文本,也可以穿插子元素。一般来说,有web服务和配置文件中看到的xml类型,其中所有元素文本都在叶元素中,然后有一些情况,如XHTML,穿插事情正在发生 如果xml模式的工作方式是所有文本信息都在叶元素中,那么可以缓冲从startElement开始的文本,并在endElement中使用累积的文本,然后清除缓冲区
这里有一篇关于SAX的好文章:什么是DefaultElementHandler?这不是一个标准类。我自己编写,每次都从DefaultHandlerXML文件格式扩展,我想在一个页面中阅读,包括该元素中的所有内容。DefaultElementHandler实际上做什么呢?很可能这就是使用up所有你的记忆。我在下面的回答中附加了DefaultElementHandler我真的不明白你的意思…请你再详细解释一下好吗?那么如果我想使用前面提到的扩展elementhandler,我做得对还是错。为什么我总是得到OOM?…确保你的sBuilder确实得到重置;你可以使用profi要查看内存发生了什么,或者如果您没有,请放置一些调试代码,以显示sBuilder的行为符合您的预期。检查您在DocumentHelper.parseDocument中实际为DOM提供了什么。清除sBuilder的正确位置在哪里?在elementHandler内部还是外部?应该在内部elementHandler,你不能等待文档的结尾来清除它。我发现它成功地处理了大约1000页,然后它得到了OOM…如何清除sBuilder?sBuilder.setLenghth0?或null?