2010-01-11 59 views
2

案例:存在需要由.NET程序解析的大型压缩xml文件。主要问题是文件太大,因此无法在内存中完全加载并解压缩。使用.NET读取压缩的xml

该文件需要逐一阅读,以解压缩这些部分后,他们是“一致的”。如果一个零件只包含一个节点的一半,那么它将不可能在任何xml结构中被解析。

每一个帮助将不胜感激。 :)

编辑:当前的解决方案部分提取整个zip文件,并将其作为xml文件写入磁盘。然后读取并解析xml。到目前为止,从我的网站没有更好的想法:)。

+2

我知道这个文件太大了,不能一次装入内存。这意味着什么“按部分解压缩”?你的意思是,作为一个流? – Cheeso 2010-01-11 15:55:33

回答

4

使用DotNetZip你可以做你的阅读XML这个:

using (var zip = ZipFile.Read("c:\\data\\zipfile.zip")) 
{ 
    using (Stream s = zip["NameOfXmlFile.xml"].OpenReader()) 
    { 
     // Create the XmlReader object. 
     using (XmlReader reader = XmlReader.Create(s)) 
     { 
      while (reader.Read()) 
      { 
       .... 
      } 
     } 
    } 
} 
+0

可以接受的答案..这就是我提到的有关.. +1 – 2010-01-11 16:12:46

0

关于您的编辑:除非你真正想要对磁盘xml文件(当然这可能是在某些情况下的情况下),我将它解压到一个MemoryStream代替。

+0

这是问题 - 文件太大而无法在内存中解压缩。成像真的很大的文件... – Alex 2010-01-11 12:07:41

+0

啊,那个大:p然后我想不是。除非你可以通过某种方式来制作流媒体内容。所以,解压缩,阅读,使用,扔在流中。但我不知道你是否可以用zip文件来做到这一点? – Svish 2010-01-11 12:28:03

+0

事实上,它可以用zip文件来完成,只是不知道要一次读取多少有效的xml。换句话说,你所描述的算法在使用时会中断:)。 – Alex 2010-01-11 12:35:34

0

嗯,你在这里有两个问题,解压缩文件的方式可以给你大量的数据和方法,以便能够读取基于一次只能读取块的XML。这与我们大多数人习惯于处理XML的方式不同,我们只是一次将它读入内存中,但您说这不是一种选择。

这意味着你将不得不使用为这种情况构建的Streams。此解决方案可以工作,但可能会受到限制,具体取决于您希望对XML数据执行的操作。你说它需要被解析,但是你能够做到这一点的唯一方式(因为你不能将它保存在内存中)应该能够以“消防水带方式”读取它,并在解析每个节点时逐步浏览。 Hopefull足够能够提取出你需要的数据或者处理它(不过你也需要它)(把它插入数据库,只提取你被嵌入的部分并将它们保存到一个更小的内存XML文件中?等等)

因此,第一份工作,从您的zip文件中获取流,使用SharpZipLib(+1到Rubens)很容易。在项目中添加对SharpZipLib dll的引用。下面是一些代码,用于从zip创建流,然后将其添加到内存流中(您可能不想那么做,但它会告诉我如何使用它来获取数据的byte [],您只需要流):

using System; 
using System.IO; 
using ICSharpCode.SharpZipLib.Zip; 
using System.Diagnostics; 
using System.Xml; 

namespace Offroadcode.Compression 
{ 
    /// <summary> 
    /// Number of handy zip functions for compressing/decompressing zip data. 
    /// </summary> 
    public class Zip 
    { 

     /// <summary> 
     /// Decompresses a btye array of previously compress data from the Compress method or any Zip program for that matter. 
     /// </summary> 
     /// <param name="bytes">Compress data as a byte array</param> 
     /// <returns>byte array of uncompress data</returns> 
     public static byte[] Decompress(byte[] bytes) 
     { 
      Debug.Write("Decompressing byte array of size: " + bytes.Length ); 

      using(ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream stream = new ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream(new MemoryStream(bytes))) 
      { 
           // Left this bit in to show you how I can read from the "stream" and save the data to another stream "mem" 
       using (MemoryStream mem = new MemoryStream()) 
       { 
        int size = 0; 
        while(true) 
        { 
         byte[] buffer = new byte[4096]; 
         size = stream.Read(buffer, 0, buffer.Length); 

         if (size > 0) 
         { 
          mem.Write(buffer, 0, size); 
         } 
         else 
         { 
          break; 
         } 
        } 

        bytes = mem.ToArray(); 
       } 
      } 

      Debug.Write("Complete, decompressed size: " + bytes.Length); 

      return bytes; 
     } 

然后,如果你按照这篇文章:从MS http://support.microsoft.com/kb/301228你应该能够合并这两个批次的代码,并开始从一个zip流:)

+0

是的,这段代码让我们解压文件在内存中的分离部分,但仍然不能帮助我们定义这部分的大小。在最好的情况下,每个部分都是有效的xml。哪个是坏的时刻... – Alex 2010-01-11 12:42:39

+0

嗯“定义大小”,你可以通过定义缓冲区大小来做到这一点?对于现在的问题,我感到困惑不解。据了解,你有一个巨大的XML文件,它不可能适合内存。此方法允许您一次处理整个文件块,但是您的代码可以将其视为一个巨大的XML文件,彻底解决它的所有问题,并执行每个节点都需要执行的操作。那不是你要做什么?如果不是,请提供更多关于您想要对XML或组成XML的详细信息。 – 2010-01-11 20:48:52

+0

你也读过MS的文章吗? – 2010-01-11 20:52:11