XDocument.Load是否会将所有数据都加载到内存中?

3

我将读取类似以下示例的大型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变量中的内容时,它才会爆炸。

2个回答

4
不,XDocument会将整个文档加载到内存中。它是否“安全”这样做取决于您需要处理的文档大小。
如果您需要处理无法放入内存的XML文件,则应使用XmlReader,但不幸的是,它的使用要困难得多。

Jon,请问你能解释一下为什么在var xml = XDocument.Load(filename);这行代码之后,使用的内存并没有立即增加吗?只有当我尝试查看该变量中的内容时,内存才会增加。 - Giorgi Nakeuri
这里我上传了一个视频:https://youtu.be/MPBmA5VGOjA 你可以看到使用的内存约为298Mb,在加载后增加到299。但在查看变量后,它会爆炸式增长。 - Giorgi Nakeuri
@GiorgiNakeuri:在调试器中查看内存占用是不可靠的,因为可能需要任意数量的额外东西来进行调试器交互。一般来说,由于垃圾回收堆的工作方式,观察.NET中的内存使用情况是棘手的。但是尝试使用XDocument.Load加载一个非常大的XML文件(例如500MB),您会看到内存使用情况上升... - Jon Skeet

1

我使用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);
                    }
                }
            }
        }
    }
}


可以使用“entry”或其他任何名称,而不是“record”。 - Giorgi Nakeuri
以上代码仅处理一个标记。需要修改代码以处理多个标记。 - jdweng
没有两个标签。标签名称未知,您不能假设它被称为您代码中的“record”。 - Giorgi Nakeuri
一个硬编码的字符串总是可以被变量替代。 - jdweng
你在开玩笑吧?你真的不理解这个问题吗?我不能使用任何变量。我事先不知道 xml 文件中标记是什么。我所知道的是我需要第一个子节点和第一个子节点的所有一级后代。你预先不知道标记名称,也不知道 xml 文件结构,然后告诉我“只需使用变量”... - Giorgi Nakeuri
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接