标签:
一、上篇回顾
上两篇都介绍了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时这两个特性可以让工作事半功倍。
标签:
原文地址:http://www.cnblogs.com/sunshineground/p/4580548.html