2010-10-19 125 views
14

我需要一个xml解析器来解析大约1.8 GB的文件。
所以分析器不应该加载所有的文件到内存。大型文件的Java XML解析器

有什么建议吗?

+0

1.8 gb是一个巨大的文本文件。在文件级不可能把它分成几块? – Owen 2010-10-19 15:01:24

+1

@Owen - 这取决于你的域名。当与来自其他人的系统的数据转储进行交互时,这种情况可能非常容易发生。 – 2010-10-19 15:03:34

+0

我没有想到,但我想我们再次需要这样一个解析器,以避免损坏的XML文件?做这种手动或任何建议怎么做都不实际? – mehmet6parmak 2010-10-19 15:05:06

回答

19

除了推荐的SAX解析,您可以使用包含在JDK(包javax.xml.stream)中的StAX API(一种SAX演变)。

+1

虽然我同意StAX通常是最好的解决方案,但在某些情况下SAX更好。如果您的文档包含大量文本内容,则AFAIR StAX API将完全读取内存中的这些文本块,并将其作为单个事件处理。 SAX解析器通常会将它分成更小的块,并将其分段供给处理程序。不保证能够利用这个机会,但是在StAX中,这个机会甚至不存在。 (我个人觉得对于流媒体API有点尴尬。) – 2010-12-15 13:15:42

+0

问候可以有人请在这里提高我的理解。因为我有关于这个问题的面试问题,我回答的关键词是'sax'和'thread',但他仍然需要第三个关键词我回答执行者线程池...他说是和?!〜答案是优先级队列can some一个解释如何 – shareef 2015-01-13 17:06:00

+0

@ wilfred-springer Coalesce是一个可以在XMLInputFactory上设置的功能 - StAX API通常以与SAX相同的方式支持此功能。例如参见FasterXML inputfactory。 – ThomasRS 2015-03-05 09:59:50

1

几乎可以使用任何SAXParser来一次传输文件。

3

将文件流式传输到SAX解析器中,并以块为单位将其读入内存中。

SAX为您提供了很多控制,并且事件驱动很有意义。 api有点难以掌握,你必须注意一些事情,比如何时调用了characters()方法,但基本思想是你编写了一个内容处理程序,当每个程序的开始和结束被调用时读取xml元素。因此,您可以跟踪文档中当前的xpath,确定哪些路径具有您感兴趣的数据,并确定哪条路径标记了要保存或切换或以其他方式处理的块的末尾。

10

使用基于SAX的解析器,它向您显示事件流中文档的内容。

3

尝试VTD-XML。我发现它比SAX更高效,更重要的是,它更易于使用。

+0

GPL的授权如何? – 2017-11-28 11:35:58

3

正如其他人所说,使用SAX解析器,因为它是一个流解析器。使用各种事件,您可以根据需要提取信息,然后在其他位置(数据库,另一个文件,您有什么)进行存储。

如果您真的只需要一小部分子集,或者只是简单归纳文件,您甚至可以将它存储在内存中。当然取决于用例。

如果您正在假脱机数据库,确保您采取一些谨慎措施,使您的过程可重新启动或任何。在1.8GB中可能发生很多可能会在中间失败的情况。

4

StAX的API是比较容易处理相比,SAX与。这里是一个用于StaX的short tutorial

+0

+10为有用的教程 – 2010-10-19 15:33:30

0

+1。它比SaX更易于使用,因为您不需要编写回调(您基本上只是循环遍历所有元素,直到完成),并且对于它可以处理的文件的大小(AFAIK)没有限制。

1

我有一个类似的问题 - 我不得不读一个完整的XML文件并在内存中创建一个数据结构。在这个数据结构上(整个事情都必须加载),我不得不做各种操作。很多XML元素包含文本(我必须在输出文件中输出这些文本,但对算法来说不重要)。首先,如这里所建议的,我使用SAX来解析文件并构建我的数据结构。我的文件是4GB,我有一个8GB的机器,所以我认为可能3GB的文件只是文本和java.lang。对于使用UTF-16的文本,字符串可能需要6GB。

如果JVM占用比计算机有物理RAM更多的空间,那么机器将交换。做一个标记+清理垃圾回收会导致页面以随机顺序访问,而且对象也会从一个对象池移动到另一个对象池,这基本上会导致机器死机。

因此,我决定把所有的字符串写入磁盘中的一个文件中(FS显然可以处理3GB的顺序写入就好了,并且在操作系统中读取它时将使用可用内存作为文件系统缓存;可能仍然有随机访问读取,但比java中的GC少)。我创建了一个小帮手类,如果它可以帮助你,欢迎下载:StringsFile javadoc | Download ZIP

StringsFile file = new StringsFile(); 
StringInFile str = file.newString("abc");  // writes string to file 
System.out.println("str is: " + str.toString()); // fetches string from file