2010-01-11 60 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