码迷,mamicode.com
首页 > Windows程序 > 详细

C#操作XML(四)

时间:2015-06-16 14:27:02      阅读:129      评论:0      收藏:0      [点我收藏+]

标签:

一、上篇回顾

  上两篇都介绍了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>

1. 使用Linq to Xml尝试

  如果使用之前介绍的Linq to Xml可以很快写出一下代码:

static void Main(string[] args)
{
    var di = new DirectoryInfo("E:\\PDF");
    XDocument doc = new XDocument(GetFolderContent(di));
            
    doc.Save(Console.Out);

    Console.ReadKey();
}

private 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消耗的内存,就算只有1Byte,1G内存也只能处理10的30次方,所以要处理完这个场景,需要多少内存啊!可以说是不可能达到的。

2. 分析

  上面的实现得益于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文档,同事保持较小的内存需求量。

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


3. 实现

  找到了XStreamingElement这个Linq to Xml的另类API后,就可以实现前面的目标了。

  XStreamingElement的用法与XElement十分相似,只需要把前面的方法稍作修改即可:  

private 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("d:\\sourcecode");
GetFolderContent(di).Save(Console.Out);

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

三、总结

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

C#操作XML(四)

标签:

原文地址:http://www.cnblogs.com/sunshineground/p/4580548.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!