我继承了一个数据存储,它使用简单的文本文件来保存文档。
文档有一些属性(日期,标题和文本),这些属性用文件名编码:< date> - < title> .txt,文件正文为文本。
然而,实际上系统中的文档具有更多属性,并且还建议添加更多属性。
切换到XML格式似乎合乎逻辑,我已经这样做了,每个文档现在都用它自己的XML文件编码。
然而,从XML读取文件现在非常慢! (其中.txt格式的2000篇文章需要几秒钟,现在2000篇.xml格式的文章需要超过10分钟)。
我使用的是DOM解析器,在我发现读取速度有多慢之后,我切换到SAX解析器,但它仍然很慢(好,更快,但仍然是10分钟)。
XML只是那么慢,还是我在做一些奇怪的事情?任何想法都将不胜感激。
系统是用JavaSE 1.6编写的。 解析器的创建方式如下:
/*
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
*/
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser;
try {
saxParser = factory.newSAXParser();
ArticleSaxHandler handler = new ArticleSaxHandler();
saxParser.parse(is, handler);
return handler.getArticle();
} catch (ParserConfigurationException e) {
throw new IOException(e);
} catch (SAXException e) {
throw new IOException(e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
logger.error(e);
}
}
}
}
private class ArticleSaxHandler extends DefaultHandler {
private URI uri = null;
private String source = null;
private String author = null;
private DateTime articleDatetime = null;
private DateTime processedDatetime = null;
private String title = null;
private String text = null;
private ArticleElement currentElement;
private final StringBuilder builder = new StringBuilder();
public Article getArticle() {
return new Article(uri, source, author, articleDatetime, processedDatetime, title, text);
}
/** Receive notification of the start of an element. */
public void startElement(String uri, String localName, String qName, Attributes attributes) {
if (builder.length() != 0) {
throw new RuntimeException(new SAXParseException(currentElement + " was not finished before " + qName + " was started", null));
}
currentElement = ArticleElement.getElement(qName);
}
public void endElement(String uri, String localName, String qName) {
final String elementText = builder.toString();
builder.delete(0, builder.length());
if (currentElement == null) {
return;
}
switch (currentElement) {
case ARTICLE:
break;
case URI:
try {
this.uri = new URI(elementText);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
break;
case SOURCE:
source = elementText;
break;
case AUTHOR:
author = elementText;
break;
case ARTICLE_DATE_TIME:
articleDatetime = getDateTimeFormatter().parseDateTime(elementText);
break;
case PROCESSED_DATE_TIME:
processedDatetime = getDateTimeFormatter().parseDateTime(elementText);
break;
case TITLE:
title = elementText;
break;
case TEXT:
this.text = elementText;
break;
default:
throw new IllegalStateException("Unexpected ArticleElement: " + currentElement);
}
currentElement = null;
}
/** Receive notification of character data inside an element. */
public void characters(char[] ch, int start, int length) {
builder.append(ch, start, length);
}
public void error(SAXParseException e) {
fatalError(e);
}
public void fatalError(SAXParseException e) {
logger.error("currentElement: " + currentElement + " ||builder: " + builder.toString() + "\n\n" + e.getMessage(), e);
}
}
private enum ArticleElement {
ARTICLE(ARTICLE_ELEMENT_NAME), URI(URI_ELEMENT_NAME), SOURCE(SOURCE_ELEMENT_NAME), AUTHOR(AUTHOR_ELEMENT_NAME), ARTICLE_DATE_TIME(
ARTICLE_DATETIME_ELEMENT_NAME), PROCESSED_DATE_TIME(PROCESSED_DATETIME_ELEMENT_NAME), TITLE(TITLE_ELEMENT_NAME), TEXT(TEXT_ELEMENT_NAME);
private String name;
private ArticleElement(String name) {
this.name = name;
}
public static ArticleElement getElement(String qName) {
for (ArticleElement element : ArticleElement.values()) {
if (element.name.equals(qName)) {
return element;
}
}
return null;
}
}
答案 0 :(得分:6)
从无缓冲流中读取数据可以解释这些性能问题。这与从文本到XML的更改没有直接关系,但可能是您的新实现不再使用BufferedInputStream
。
详细说明该路径,检查此is
是否已缓冲:
saxParser.parse(is, handler);
答案 1 :(得分:0)
使用SAX解析器加载速度太慢,我也遇到了这个问题。该问题实际上与我的XML文件有关,该文件具有W3C的DTD参考:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" >
<html xmlns="http://www.w3.org/TR/1999/REC-html-in-xml" xml:lang="en"
lang="en">
“ Core Java,第II卷”第2章中有关SAX和XML的摘录描述了正在发生的事情以及如何添加地址:
XHTML文件以包含DTD参考的标记开头,并且 解析器将要加载它。可以理解,W3C不太合适 很乐意提供数十亿份文件,例如 www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd。有一次,他们拒绝了 总体而言,但在撰写本文时,他们以 冰川的步伐。如果您不需要验证文档,只需致电
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
这为我解决了。另外,我使用IntelliJ IDE演示我的XML文件具有一个额外的(不必要的)<HTML>
标签和一个额外的<meta charset="UTF-8"/>
。这帮助我摆脱了一些SAX例外。