2

我继承了一个数据存储,它使用简单的文本文件来保存文档。

文档有一些属性(日期、标题和文本),它们被编码在一个文件名中:<date>-<title>.txt,文件的主体是文本。

然而实际上系统中的文档有更多的属性,甚至更多的再次被提议添加。

切换到 XML 格式似乎是合乎逻辑的,我已经这样做了,现在每个文档都编码在它自己的 XML 文件中。

然而,从 XML 中读取文件现在非常慢!(以前 .txt 格式的 2000 篇文章需要几秒钟,现在 .xml 格式的 2000 篇文章需要 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;
        }
    }

4

2 回答 2

6

从无缓冲的流中读取数据可以解释这些性能问题。这与从文本到 XML 的更改没有直接关系,但可能碰巧您的新实现不再使用 a BufferedInputStream


按照该路径,详细检查是否is已缓冲:

saxParser.parse(is, handler);
于 2010-08-19T11:09:22.487 回答
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, Volume II”第 2 章关于 SAX 和 XML 的摘录描述了正在发生的事情以及如何解决:

XHTML 文件以包含 DTD 引用的标记开头,解析器将要加载它。可以理解,W3C 不太乐意提供数十亿份文件副本,例如 www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd。有一次,他们完全拒绝了,但在撰写本文时,他们以缓慢的速度为 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 异常。

于 2020-05-24T04:46:27.993 回答