【问题标题】:Does XDocument.Load loads all data into memory?XDocument.Load 是否将所有数据加载到内存中?
【发布时间】:2017-03-15 04:53:55
【问题描述】:

我必须读取大型 xml 文件的根节点的所有一级节点,如下所示:

<root>
 <record n="1"><a/><b/><c/></record>
 <record n="2"><a/><b/><c/></record>
 <record n="3"><a/><b/><c/></record>
</root>

我的代码如下:

var xml = XDocument.Load(filename);

var firstNode = xml?.Root?.Descendants()?.FirstOrDefault();

var elements = firstNode?.Elements();

我只需要获取根的第一个孩子和它的所有第一级后代。这段代码运行良好,但问题是:这样阅读是否安全?我猜它不会将所有数据加载到内存中 - 只有 xml 文件的结构?

我看到调试时内存没有增加。只有当我真正尝试查看 xml 变量中的内容时,它才会爆炸。

【问题讨论】:

    标签: c# xml


    【解决方案1】:

    不,XDocument 将整个文档加载到内存中。这样做是否“安全”取决于您需要处理的文档大小。

    如果您需要处理无法放入内存的 XML 文件,您会想要使用 XmlReader,但不幸的是,它很难使用。

    【讨论】:

    • Jon,你能解释一下为什么在var xml = XDocument.Load(filename); 行之后没有立即增加使用的内存。只有当我尝试查看该变量中的内容时它才会增加。
    • 这里我上传了一个视频:youtu.be/MPBmA5VGOjA 你可以看到使用的内存是~298Mb,加载后增加到299。但是查看变量后会爆炸。
    • @GiorgiNakeuri:查看调试器中占用的内存是不可靠的,因为调试器交互可能需要许多额外的东西。通常,由于垃圾收集堆的工作方式,在 .NET 中观察内存使用情况很棘手。但是尝试在使用 XDocument.Load 时加载一个非常大的 XML 文件(例如 500MB),您会看到使用率上升...
    【解决方案2】:

    我使用 xmlreader 和 xdocument 的组合。更新代码以动态获取第一个标签名称。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.Xml.Linq;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            const string FILENAME = @"c:\temp\test.xml";
            static void Main(string[] args)
            {
                XmlReader reader = XmlReader.Create(FILENAME);
                reader.ReadStartElement(); //read root
                XElement.ReadFrom(reader);// read \n
                XElement record = null;
                string recordName = "";
                Boolean first = true;
                while (!reader.EOF)
                {
                    if (first)
                    {
                        record = (XElement)XElement.ReadFrom(reader);
                        first = false;
                        recordName = record.Name.LocalName;
                    }
                    else
                    {
                        if (reader.Name != recordName)
                        {
                            reader.ReadToFollowing(recordName);
                        }
                        if (!reader.EOF)
                        {
                            record = (XElement)XElement.ReadFrom(reader);
                        }
                    }
                }
            }
        }
    }

    【讨论】:

    • “记录”可以是“条目”或其他任何内容。
    • 以上代码只处理标签。必须修改代码以处理多个标签。
    • 没有 2 个标签。标签名称是未知的,你不能假设它在你的代码中被称为“记录”......
    • record 是一个字符串,所以你可以用任何字符串变量替换。
    • 我不知道为什么理解我的担忧这么难。我不能用任何其他字符串替换这个字符串。我正在创建一个处理此 xml 文件的自动化应用程序。不仅标签名称,甚至 xml 的结构都是事先未知的。但我提供的结构是最常见的一种。我只是无法在应用程序中对标签名称“记录”进行硬编码。我也不能硬编码任何其他可能的标签名称。它应该是动态的。还是不清楚吗?
    猜你喜欢
    • 2012-11-17
    • 1970-01-01
    • 2021-04-14
    • 1970-01-01
    • 2010-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-03
    相关资源
    最近更新 更多