• c#操作Xml(五)


    上集回顾

        上两集都介绍了Linq to Xml的相关用法,需要注意的一点是Linq to Xml是in-memory的处理方式,所以有多少节点,就要消耗多少内存,如果这个xml很大,但系统内存却有限的情况下怎么办哪?

    设置目标

        今天要做的是把某目录下的所有文件和目录输出到一个xml里面去,例如:

    <?xml version="1.0" encoding="gb2312"?>
    <
    folder name="bin">
    <
    folder name="Debug">
    <
    file name="ConsoleApplication6.exe" />
    <
    file name="ConsoleApplication6.exe.config" />
    <
    file name="ConsoleApplication6.pdb" />
    <
    file name="ConsoleApplication6.vshost.exe" />
    <
    file name="ConsoleApplication6.vshost.exe.config" />
    <
    file name="ConsoleApplication6.vshost.exe.manifest" />
    </
    folder>
    <
    folder name="Release">
    <
    file name="ConsoleApplication6.exe" />
    <
    file name="ConsoleApplication6.exe.config" />
    <
    file name="ConsoleApplication6.pdb" />
    <
    file name="ConsoleApplication6.vshost.exe" />
    <
    file name="ConsoleApplication6.vshost.exe.config" />
    <
    file name="ConsoleApplication6.vshost.exe.manifest" />
    </
    folder>
    </
    folder>

        当然这个需要可以作用于c盘根目录,也就是需要处理相当多的文件和目录。

    使用Linq to Xml尝试

        如果用前两集中介绍的Linq to Xml来做,可以很快地写出:

    var di = new DirectoryInfo("..");
    XDocument doc = new XDocument(GetFolderContent(di));
    doc.Save(Console.Out);

        以及:

    static XElement GetFolderContent(DirectoryInfo di)
    {
    return new XElement("folder",
    new XAttribute("name", di.Name),
    from subDir in di.GetDirectories()
    select GetFolderContent(subDir),
    from file in di.GetFiles()
    select new XElement("file", new XAttribute("name", file.Name)));
    }

        但是,需要注意一点,Linq to Xml是in-memory的方式工作的,也就是如果有1000级的目录嵌套,每级有100个子目录,那么就有100^1000个XElement在内存中创建出来,好吧,这么计算一下,整个过程需要多少内存吧,10的2000次方*每一个XElement消耗的内存,就算只有1个Byte,1G内存也只能处理10的30次方,所以要处理完这个场景,说需要的多少内存可以说是不可能达到的。

    分析

        上面的实现得益于Linq to Xml API的简易,但是却有受制于Linq to Xml的in-memory模型,要是有一种既可以受益于Linq to Xml的简易,又可以使用非in-memory的模型就两全其美了。

        天下有这么好的事情吗?先不要急于下定论,让我们来查查msdn吧:如何:执行大型 XML 文档的流式转换

        这里提到了一个XStreamingElement的类,仅仅从名称上,我们就可以知道,这个类是一个类似XElement的类型,但是它又是一个类似Stream的类,并不是in-memory的,当然具体怎么说还要看msdn

        msdn中明确说明:表示支持延迟流输出的 XML 树中的元素。

        而且在备注中说到:如果从输入源(如文本文件)进行流式处理,则可以读取非常大的文本文件,并生成非常大的 XML 文档,同时保持较小的内存需求量。

        也就是明确了XStreamingElement这个类本身就是(或类似)流式处理的,并不像普通的XElement的in-memory的处理方式。

    实现

        找到了XStreamingElement这个Linq to Xml的另类API之后,就可以实现了前面的目标了,XStreamingElement的用法与XElement十分相似,因此只需要把前面的方法稍作修改即可:

    static XStreamingElement GetFolderContent(DirectoryInfo di)
    {
    return new XStreamingElement("folder",
    new XAttribute("name", di.Name),
    from subDir in di.GetDirectories()
    select GetFolderContent(subDir),
    from file in di.GetFiles()
    select new XElement("file", new XAttribute("name", file.Name)));
    }

        不过,需要额外修改一下外面的调用方式:

    var di = new DirectoryInfo(@"C:\");
    GetFolderContent(di).Save(Console.Out);

        这里必须要用XStreamingElement的Save方法,否则延迟求解的特性可能会失效。

    总结和下集预告

        本集介绍了Linq to Xml中的异类:XStreamingElement,既得益于Linq to Xml的简易,又拥有streaming的小内存特性,在操作超大xml是这两个特性可以让工作事半功倍。

        但是,如果一个需要流处理的需求,并且部署环境没有安装.net 3.5 framework的话,怎么办哪,这使我们不得不回到xml reader和xml writer的时代,下集将介绍如何使用这两者。

  • 相关阅读:
    ubuntu上如何安装和卸载google chrome 浏览器
    另眼相看“那些争议最大的编程观点”
    读完了csapp(中文名:深入理解计算机系统)
    SSL工作原理
    linux signal 处理
    PCB设计资料:看到最后才知道是福利
    String.Format使用方法
    matlab三维画图
    spin_lock &amp; mutex_lock的差别?
    Hibernate Criterion
  • 原文地址:https://www.cnblogs.com/vwxyzh/p/1617978.html
Copyright © 2020-2023  润新知