用于大文件的 Java XML 解析器
Posted
技术标签:
【中文标题】用于大文件的 Java XML 解析器【英文标题】:Java XML Parser for huge files 【发布时间】:2011-04-27 13:12:24 【问题描述】:我需要一个 xml 解析器来解析大约 1.8 GB 的文件。 所以解析器不应该将所有文件加载到内存中。
有什么建议吗?
【问题讨论】:
1.8 gb 是一个巨大的文本文件。不能在文件级别将其分解成块吗? @Owen - 这取决于您的域。当与其他人系统的数据转储接口时,这种情况很容易发生。 我没有想到这一点,但我想我们再次需要这样的解析器来避免破坏 xml 文件?手动进行这种操作或任何建议如何操作都不实用? @Nick - 我没有考虑到这一点。好点子。 你想用它做什么? 【参考方案1】:使用几乎任何SAX Parser 一次流一点文件。
【讨论】:
【参考方案2】:将文件流式传输到 SAX 解析器并以块的形式将其读入内存。
SAX 为您提供了很多控制权,并且事件驱动是有道理的。 api有点难掌握,你必须注意一些事情,比如调用 characters() 方法的时间,但基本思想是你编写一个内容处理程序,在每个开始和结束时调用xml 元素被读取。因此,您可以跟踪文档中的当前 xpath,确定哪些路径具有您感兴趣的数据,并确定哪个路径标记了您要保存、移交或以其他方式处理的块的结尾。
【讨论】:
【参考方案3】:使用基于 SAX 的解析器,以事件流的形式向您呈现文档内容。
【讨论】:
【参考方案4】:试试VTD-XML。我发现它比 SAX 性能更高,更重要的是,它更易于使用。
【讨论】:
授权哪个 GPL 怎么样?【参考方案5】:正如其他人所说,使用 SAX 解析器,因为它是流式解析器。使用各种事件,您可以根据需要提取信息,然后将其动态存储在其他地方(数据库、另一个文件、您有什么)。
如果您真的只需要一个次要子集,或者您只是对文件进行汇总,您甚至可以将其存储在内存中。当然取决于用例。
如果您要假脱机到数据库,请确保您注意使您的进程可重新启动或其他。 1.8GB 中可能会发生很多事情,但中间可能会失败。
【讨论】:
【参考方案6】:除了推荐的 SAX 解析之外,您还可以使用 JDK(包 javax.xml.stream)中包含的 StAX API(一种 SAX 演变)。
StAX 项目主页:http://stax.codehaus.org/Home 简介:http://www.xml.com/pub/a/2003/09/17/stax.html Javadoc:https://docs.oracle.com/javase/8/docs/api/javax/xml/stream/package-summary.html【讨论】:
虽然我同意 StAX 通常是最好的解决方案,但在某些情况下 SAX 更好。如果您的文档包含大块文本内容,那么 AFAIR StAX API 将完全读取内存中的这些文本块并将其作为单个事件处理。 SAX 解析器通常会将其拆分为更小的块并分段提供给您的处理程序。不能保证利用这个机会,但在 StAX 甚至不存在这个机会。 (我个人觉得流式 API 有点尴尬。) 欢迎有人在这里提高我的理解。因为我有关于这个的面试问题,我回答的关键词是sax
和thread
,但他仍然需要第三个关键词我回答了执行者线程池......他说是的?!~答案是优先队列可以一些一个解释如何
@wilfred-springer Coalesce 是一项可以在 XMLInputFactory 上设置的功能 - StAX API 通常以与 SAX 相同的方式支持此功能。例如,参见 FasterXML 输入工厂。【参考方案7】:
与 SAX 相比,StAX API 更容易处理。这是short tutorial
【讨论】:
【参考方案8】:StaX +1。它比 SaX 更容易使用,因为你不需要编写回调(你基本上只是循环所有的 while 元素直到你完成)并且它(AFAIK)对它可以处理的文件的大小没有限制.
【讨论】:
【参考方案9】:我遇到了类似的问题 - 我必须读取整个 XML 文件并在内存中创建数据结构。在这个数据结构上(必须加载整个东西)我必须做各种操作。许多 XML 元素包含文本(我必须在输出文件中输出,但对算法而言并不重要)。
首先,按照这里的建议,我使用 SAX 来解析文件并构建我的数据结构。我的文件是 4GB,而我有一台 8GB 的机器,所以我认为文件中的 3GB 可能只是文本,而 java.lang.String 使用其 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
【讨论】:
以上是关于用于大文件的 Java XML 解析器的主要内容,如果未能解决你的问题,请参考以下文章