Java 如何通过StAX修改一个巨大的XML文件?
我有一个巨大的XML(~2GB),我需要添加新元素并修改旧元素。例如,我有:Java 如何通过StAX修改一个巨大的XML文件?,java,xml,xml-parsing,stax,Java,Xml,Xml Parsing,Stax,我有一个巨大的XML(~2GB),我需要添加新元素并修改旧元素。例如,我有: <books> <book>....</book> ... <book>....</book> </books> 但结果如下: <books> <book>....</book> .... <book>....</book> </books
<books>
<book>....</book>
...
<book>....</book>
</books>
但结果如下:
<books>
<book>....</book>
....
<book>....</book>
</books><index></index>
....
....
....
有什么想法吗?很清楚为什么它会这样做。实际上,您正在以输出附加模式打开现有文件,并在末尾写入元素。这显然与你想做的相矛盾 (旁白:考虑到输入端可能会看到输出端添加到文件末尾的元素,我很惊讶它的工作原理如此之好。事实上,像Evgeniy Dorofev的例子所给出的例外情况正是我所期望的。问题是,如果您试图同时读写一个文本文件,那么nd无论读写器使用任何形式的缓冲,无论是显式的还是隐式的,读写器都容易看到部分状态。) 要解决此问题,您必须从读取一个文件开始,然后写入另一个文件。追加将不起作用。然后,您必须安排将从输入文件读取的元素、属性、内容等复制到输出文件。最后,您需要在适当的位置添加额外的元素
是否有可能以类似RandomAccessFile的模式打开XML文件,但使用StAX方法写入 不,这在理论上是不可能的。为了能够以“随机”的方式浏览XML文件的结构文件,首先需要解析整个内容并建立所有元素所在的索引。即使这样,XML仍然作为文件中的字符存储,随机访问不允许插入和删除文件中间的字符。 也许您最好将XSL和SAX风格的解析器结合起来;例如,类似于这篇IBM文章的内容:试试这个
XMLInputFactory inFactory = XMLInputFactory.newInstance();
XMLEventReader eventReader = inFactory.createXMLEventReader(new FileInputStream("1.xml"));
XMLOutputFactory factory = XMLOutputFactory.newInstance();
XMLEventWriter writer = factory.createXMLEventWriter(new FileWriter(file));
XMLEventFactory eventFactory = XMLEventFactory.newInstance();
while (eventReader.hasNext()) {
XMLEvent event = eventReader.nextEvent();
writer.add(event);
if (event.getEventType() == XMLEvent.START_ELEMENT) {
if (event.asStartElement().getName().toString().equalsIgnoreCase("book")) {
writer.add(eventFactory.createStartElement("", null, "index"));
writer.add(eventFactory.createEndElement("", null, "index"));
}
}
}
writer.close();
注释
新的FileWriter(file,true)将附加到文件末尾,您几乎不需要它
equalsIgnoreCase(“书”)是个坏主意,因为XML是区分大小写的也许JavaEE教程中的这个StAX读写示例有助于:
您可以在此处下载教程示例:不幸的是,这段代码不起作用。NetBeans给了我一个错误:“原因:javax.xml.stream.XMLStreamException:ParseError at[row,col]:[4,2]消息:xml文档结构必须在同一实体内开始和结束。在com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.nextcom.sun.xml.internal.stream.XMLEventReaderImpl.nextEvent(XMLEventReaderImpl.java:83)上的…54 more'而且它删除了文件的所有内容…有什么异常吗?我在发布之前用您的xml测试了它。我刚刚尝试了它。同样的异常:'由:javax.xml.stream.XMLStreamException:ParseError at[row,col]:[3,5]消息:XML文档结构必须在同一实体内开始和结束。com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.next(XMLStreamReaderImpl.java:598)在com.sun.XML.internal.stream.XMLEventReaderImpl.nextEvent(XMLEventReaderImpl.java:83)在library.controllers.BookCardController.saveToXML(BookCardController.java:138)…54 more“我真的不知道为什么,但另外,此代码会清除我的文件。嗯,似乎此异常是因为我使用了相同的文件作为输入和输出。在选择不同的目标文件后,代码开始工作,但…输出如下:“”。我需要将元素包含到现有XML中。如果仅保留y此XMLEvent event=eventReader.nextEvent();writer.add(event);在应该获得输出==输入的循环中,它不能丢失,请尝试调试
<books>
<book>....</book>
....
<book>....</book>
</books><index></index>
XMLInputFactory inFactory = XMLInputFactory.newInstance();
XMLEventReader eventReader = inFactory.createXMLEventReader(new FileInputStream("1.xml"));
XMLOutputFactory factory = XMLOutputFactory.newInstance();
XMLEventWriter writer = factory.createXMLEventWriter(new FileWriter(file));
XMLEventFactory eventFactory = XMLEventFactory.newInstance();
while (eventReader.hasNext()) {
XMLEvent event = eventReader.nextEvent();
writer.add(event);
if (event.getEventType() == XMLEvent.START_ELEMENT) {
if (event.asStartElement().getName().toString().equalsIgnoreCase("book")) {
writer.add(eventFactory.createStartElement("", null, "index"));
writer.add(eventFactory.createEndElement("", null, "index"));
}
}
}
writer.close();