Java 巨大的XML文件到文本文件
我有一个巨大的XML文件(15GB)。我想将XML文件中的“文本”标记转换为单个页面 示例XML文件:Java 巨大的XML文件到文本文件,java,xml,Java,Xml,我有一个巨大的XML文件(15GB)。我想将XML文件中的“文本”标记转换为单个页面 示例XML文件: <root> <page> <id> 1 </id> <text> .... 1000 to 50000 lines of text </text> </page> ... Like wise 2 Million `page
<root>
<page>
<id> 1 </id>
<text>
.... 1000 to 50000 lines of text
</text>
</page>
... Like wise 2 Million `page` tags
</root>
此代码运行良好。(忽略任何小错误)。根据我的理解,XMLStreamConstants.CHARACTERS会对文本标记的每一行进行迭代。如果文本标记中有10000行,则XMLStreamConstants.CHARACTERS将在接下来的10000行中迭代。有没有更好的方法来提高性能?您的代码看起来很标准。
但是,您能否尝试将FileInputStream包装到BufferedInputStream中,并告诉我们这是否有帮助?
BufferedInputstream为您节省了对操作系统的一些本机调用,因此有机会获得更好的性能。
您必须调整缓冲区大小以获得最佳性能。根据JVM内存分配设置一些大小。尝试使用SAX解析器进行解析,因为DOM将尝试解析整个内容并将其放入内存中。因此,您会遇到内存异常。SAX解析器不会一次解析整个内容。我可以看到一些可能的解决方案,它们可能会帮助您:
BufferedInputStream
而不是简单的FileInputStream
来减少磁盘操作的数量StringBuilder
来创建页面内容,而不是字符串链接-Xmx
选项),以防2GB示例内存受限文件输入流周围使用BufferedInputStream
。
FileWriter
周围使用BufferedWriter
如果解析XML文件是主要问题,请考虑使用,即扩展版本,因为它支持文件高达256GB。
由于它基于非抽取式文档解析,因此内存效率很高,使用XPath查询/提取文本也非常快。您可以从中阅读有关此方法和VTD-XML的更多详细信息。什么是
pageContent
?它似乎是一个字符串
。一个简单的优化方法是使用StringBuilder
;它可以附加字符串,而不必像String
s+=
那样制作字符串的全新副本(如果您知道开始的长度,还可以使用初始保留容量来构造它,以减少内存重新分配和复制)
串接String
s是一个缓慢的操作,因为字符串在Java中是不可变的;每次调用a+=b
时,它必须分配一个新字符串,将a
复制到该字符串中,然后将b
复制到该字符串的末尾;使每个连接O(n)wrt。两个字符串的总长度。附加单个字符也是如此<另一方面,代码>StringBuilder在追加时具有与阵列列表
相同的性能特征。因此,你有:
pageContent += chars.getData() + '\n';
改为将pageContent
更改为StringBuilder
,并执行以下操作:
pageContent.append(chars.getData()).append('\n');
此外,如果您对其中一个字符串的长度上限有一个猜测,则可以将其传递给StringBuilder
构造函数,以分配初始容量,并减少必须进行内存重新分配和完整复制的机会
顺便说一句,另一种选择是完全跳过
StringBuilder
,直接将数据写入输出文件(假设您没有先处理数据)。如果您这样做,并且性能受I/O限制,那么在不同的物理磁盘上选择一个输出文件会有所帮助。出于好奇,您当前加载和解析该文件需要多长时间?我已经解析了2GB文件。花了35分钟..什么是pageContent
?它是一个字符串
?如果是这样,一个简单的优化方法就是使用StringBuilder
;它可以附加字符串,而不必像String
s+=
那样制作字符串的全新副本(如果您知道开始的长度,还可以使用初始保留容量来构造它,以减少内存重新分配和副本).恐怕你要花很长时间才能浏览2GB的文件。。。。我对StAX不太熟悉,但在SAX中,字符事件不是每行而是每解析缓冲区中断,可能是多行或一行的一部分,这取决于行的长度以及文本内容启动时您恰好在解析器的输入缓冲区中的位置。为什么不使用可用库来提取内容呢。WikiXMLJ是一个非常好的库,因为他将其替换为一个STAX解析器,该解析器的性能将与SAX解析器一样好。从某种意义上说,它为您节省了大量的系统调用,实际上,默认的缓冲区大小8192对于几乎所有情况都是完全足够的。
pageContent.append(chars.getData()).append('\n');