我有一个巨大的XML文件(15 GB).我想将XML文件中的"text"标记转换为单个页面.
示例XML文件:
<root>
<page>
<id> 1 </id>
<text>
.... 1000 to 50000 lines of text
</text>
</page>
... Like wise 2 Million `page` tags
</root>
Run Code Online (Sandbox Code Playgroud)
我最初使用DOM解析器,但它会抛出JAVA OUT OF MEMORY(有效).现在,我使用STAX编写了JAVA代码.它运作良好,但性能非常慢.
这是我写的代码:
XMLEventReader xMLEventReader = XMLInputFactory.newInstance().createXMLEventReader(new FileInputStream(filePath));
while(xMLEventReader.hasNext()){
xmlEvent = xMLEventReader.nextEvent();
switch(xmlEvent.getEventType()){
case XMLStreamConstants.START_ELEMENT:
if( element == "text")
isText = true;
break;
case XMLStreamConstants.CHARACTERS:
chars = (Characters) xmlEvent;
if(! (chars.isWhiteSpace() || chars.isIgnorableWhiteSpace()))
if(isText)
pageContent += chars.getData() + '\n';
break;
case XMLStreamConstants.END_ELEMENT:
String elementEnd = (((EndElement) xmlEvent).getName()).getLocalPart();
if( elementEnd == "text" )
{
createFile(id, pageContent);
pageContent = "";
isText = false;
}
break;
}
}
Run Code Online (Sandbox Code Playgroud)
这段代码运行良好.(忽略任何小错误).根据我的理解,XMLStreamConstants.CHARACTERS迭代文本标记的每一行.如果TEXT标记中有10000行,则XMLStreamConstants.CHARACTERS将迭代下一行10000行.有没有更好的方法来改善性能..?
什么是pageContent
?它似乎是一个String
. 立即进行的一个简单的优化是使用 aStringBuilder
来代替;它可以附加字符串,而不必像String
s+=
那样制作字符串的全新副本(如果您一开始就知道长度,您也可以使用初始保留容量来构造它,以减少内存重新分配和副本)。
连接String
s 是一个缓慢的操作,因为字符串在 Java 中是不可变的;每次调用a += b
它时都必须分配一个新字符串,复制a
到其中,然后复制b
到它的末尾;使每个串联都为 O(n)。两个字符串的总长度。附加单个字符也是如此。StringBuilder
另一方面,具有与ArrayList
附加时相同的性能特征。所以你有:
pageContent += chars.getData() + '\n';
Run Code Online (Sandbox Code Playgroud)
相反,更改pageContent
为 aStringBuilder
并执行以下操作:
pageContent.append(chars.getData()).append('\n');
Run Code Online (Sandbox Code Playgroud)
此外,如果您猜测这些字符串之一的长度上限,则可以将其传递给StringBuilder
构造函数以分配初始容量,并减少必须完成内存重新分配和完整复制的机会。
顺便说一句,另一种选择是完全跳过StringBuilder
并将数据直接写入输出文件(假设您没有首先以某种方式处理数据)。如果您这样做,并且性能受到 I/O 限制,那么选择不同物理磁盘上的输出文件会有所帮助。