17

我需要在 C# 中对相当大的 XML 文件(这里可能超过千兆字节)进行一些处理,包括执行一些复杂的 xpath 查询。我遇到的问题是,我通常通过 System.XML 库执行此操作的标准方式喜欢在对整个文件执行任何操作之前将整个文件加载到内存中,这可能会导致这种大小的文件出现内存问题。

我根本不需要更新文件,只需阅读它们并查询其中包含的数据。一些 XPath 查询非常复杂,并且涉及多个级别的父子类型关系——我不确定这是否会影响使用流读取器而不是将数据作为块加载到内存中的能力。

我可以看到使其工作的一种方法是使用基于流的方法执行简单的分析,并且可能将 XPath 语句包装到 XSLT 转换中,然后我可以在文件中运行,尽管它看起来有点复杂。

或者,我知道 XPath 查询不会遇到某些元素,所以我想我可以根据它的原始树结构将文档分成一系列较小的片段,这些片段可能足够小,可以在内存中处理而无需造成太大的破坏。

我试图在这里解释我的目标,所以如果我在一般方法方面完全错误的树,我相信你们可以让我正确......

4

10 回答 10

9

XPathReader 就是答案。它不是 C# 运行时的一部分,但可以从 Microsoft 下载。这是一篇MSDN 文章

如果您使用 XmlTextReader 构造 XPathReader,您将获得流式读取的效率以及 XPath 表达式的便利性。

我没有在千兆字节大小的文件上使用它,但我已经在几十兆字节的文件上使用它,这通常足以减慢基于 DOM 的解决方案的速度。

引用以下内容:“XPathReader 提供了以流方式在 XML 文档上执行 XPath 的能力”。

从微软下载

于 2009-04-04T06:44:51.810 回答
2

技嘉 XML 文件!我不羡慕你这个任务。

有什么方法可以更好地发送文件吗?例如,它们是通过网络发送给您的吗?如果它们是一种更有效的格式,对所有相关人员来说可能会更好。将文件读入数据库并不是一个坏主意,但确实可能非常耗时。

我不会尝试通过读取整个文件在内存中完成所有操作 - 除非您有 64 位操作系统和大量内存。如果文件变成 2、3、4GB 怎么办?

另一种方法是读入 XML 文件并使用 SAX 解析文件并根据某些逻辑拆分写出较小的 XML 文件。然后,您可以使用 XPath处理这些。我在 20-30MB 的文件上使用了 XPath,它非常快。我最初打算使用 SAX,但我想我会尝试一下 XPath,但它的速度之快让我感到惊讶。我节省了很多开发时间,每次查询可能只损失了 250 毫秒。我使用 Java 进行解析,但我怀疑 .NET 几乎没有区别。

我确实读过 XML::Twig(一个 Perl CPAN 模块)是明确编写的,用于处理基于 SAX 的 XPath 解析。你能用不同的语言吗?

这也可能有助于https://web.archive.org/web/1/http://articles.techrepublic%2ecom%2ecom/5100-10878_11-1044772.html

于 2009-01-03T10:46:45.037 回答
2

http://msdn.microsoft.com/en-us/library/bb387013.aspx有一个利用 XStreamingElement 的相关示例。

于 2011-02-16T09:31:13.803 回答
1

你已经概述了你的选择。

要么您需要放弃 XPath 并使用 XmlTextReader,要么您需要将文档分成可管理的块,您可以在这些块上使用 XPath。

如果您选择后者使用 XPathDocument,它的只读限制允许更好地使用内存。

于 2009-01-02T16:49:02.433 回答
1

为了使用标准 .NET 类执行 XPath 查询,需要将整个文档树加载到内存中,如果它可能占用 1 GB,这可能不是一个好主意。恕我直言,XmlReader是处理此类任务的好类。

于 2009-01-02T16:49:36.643 回答
1

我认为最好的解决方案是制作您自己的 xml 解析器,它可以读取小块而不是整个文件,或者您可以将大文件拆分为小文件,并对这些文件使用 dotnet 类。问题是在整个数据可用之前您无法解析某些数据,因此我建议使用您自己的解析器而不是 dotnet 类

于 2009-01-03T11:14:44.277 回答
1

看来您已经尝试过使用XPathDocument并且无法在内存中容纳已解析的 xml 文档

如果是这种情况,在开始拆分文件之前(这最终是正确的决定!)您可以尝试使用Saxon XSLT/XQuery 处理器。它具有加载的 XML 文档(“小树”模型)的非常有效的内存表示。此外, Saxon SA(shema-aware 版本,不是免费的)有一些流媒体扩展在此处阅读有关此内容的更多信息。

于 2009-01-02T17:27:53.697 回答
1

将整个内容读入数据库然后使用临时数据库怎么样?这可能会更好,因为这样您的查询可以使用 TSQL 更有效地完成。

于 2009-01-02T18:38:33.913 回答
0

您是否尝试过 XPathDocument?此类针对有效处理 XPath 查询进行了优化。

如果您不能使用 XPathDocument 有效地处理您的输入文档,您可以考虑使用 XmlReader 预处理和/或拆分您的输入文档。

于 2009-01-02T16:48:50.763 回答
0

由于在您的情况下,数据大小可以在 Gbs 中运行,您是否考虑过使用 ADO.NET 和 XML 作为数据库。除此之外,内存占用不会很大。

另一种方法是使用 Linq to XML 并使用 XElementStream 等元素。希望这可以帮助。

于 2010-03-19T19:11:54.217 回答