[C#]使用SharpZip做壓縮解壓縮(Zip and Unzip)

  • 5295
  • 0
  • C#
  • 2015-02-19

做壓縮與解壓縮對現在來說,是滿普遍的需求,特別是在傳送大資料時,未了減少傳送的時間,所以也會先壓縮過資料再來傳送,而在.Net中,從2.0開始也有提供壓縮的方法-

System.IO.Compression下的GZip,不過在這邊要介紹另外一種第三方套件,叫做SharpZip,因為他可以支援到.Net1.1 並且在壓縮的格式上提供了更多,Zip、GZip、Tar與BZip2等等。

而這邊筆記一下,自己整理後使用的方法,由程式碼片段做記錄。

前言

 


 

做壓縮與解壓縮對現在來說,是滿普遍的需求,特別是在傳送大資料時,未了減少傳送的時間,所以也會先壓縮過資料再來傳送,而在.Net中,從2.0開始也有提供壓縮的方法-

System.IO.Compression下的GZip,不過在這邊要介紹另外一種第三方套件,叫做SharpZip,因為他可以支援到.Net1.1 並且在壓縮的格式上提供了更多,Zip、GZip、Tar與BZip2等等。

而這邊筆記一下,自己整理後使用的方法,由程式碼片段做記錄。

 

使用SharpZip做壓縮解壓縮

 


 

首先,SharpZip可以支援的.Net版本可以到 .NET 1.1, .NET 2.0 (3.5, 4.0), .NET CF 1.0, .NET CF 2.0之多,另外他支援的壓縮方式也比.Net原生的多種,所以使其變成滿歡迎的套件,從Nuget上也可以直接安裝,而這邊我是使用下載的方式,解壓縮後會有三個資料夾,如下:

SharpZip

 

選擇其中一個參考以後,加入


using ICSharpZipCode.SharpZipLib;
using ICSharpZipCode.SharpZipLib.Zip;
using ICSharpCode.Sharpe; //可以使用StreamUtils 做串流的資ZipLib.Cor料複製

再來介紹,壓縮檔案與解壓縮檔案的程式片段:

 

檔案壓縮 與檔案解壓縮

 

檔案壓縮

首先是壓縮檔案,需要把資料先轉換成FileStream,主要是透過ZipEntry這個類別的物件在做壓縮工作,在初始化ZipEntry時可指定名稱,如果已經決定要存放資料在哪裡,可傳入實體檔案路徑,並且把此物件放置ZipOutputStream,爾後透過此物件來寫入資料到裡面時,便會做壓縮。


/// <summary>
/// 壓縮來源檔案為ZIP檔案,密碼壓縮
/// </summary>
/// <param name="inFullPathName">來源檔案路徑名稱</param>
/// <param name="outZipFullPathName">輸出成Zip的檔案來源路徑</param>
/// <param name="password">壓縮的密碼</param>
public static void CompressionToFile(string inFullPathName,string outZipFullPathName,string password)
{           
       using (FileStream output = new FileStream(outZipFullPathName, FileMode.Create, FileAccess.Write))
       using (FileStream input = new FileStream(inFullPathName, FileMode.Open, FileAccess.Read))
       using (ZipOutputStream zipOut = new ZipOutputStream(output))
       {
               zipOut.Password = password;
               ZipEntry entry = new ZipEntry(inFullPathName);
               byte[] buffer = new byte[4096];
               entry.DateTime = DateTime.Now;
               zip.PutNextEntry(entry);
               int readLength;
               do
               {
                    readLength = input.Read(buffer, 0, buffer.Length);
                   if (readLength > 0)
                   {
                         zip.Write(buffer, 0, readLength);
                   }
              }while (readLength > 0);
        }
}

 

檔案解壓縮

再來是解壓縮檔案的部分,此部分是對原檔案做解壓縮,解壓縮的路徑透過ZipEntry的Name屬性來做路徑的設定,先把檔案的串流放至到ZipInputStream 物件後,在透過此物件的GetNextEntry()方法取得ZipEntry,拿取到解壓縮的資料與實體,便可以讀取解壓縮的資料了。


/// <summary>
/// 解壓縮"需要密碼"的Zip檔案,路徑是壓縮的原檔案路徑名稱
/// </summary>
/// <param name="sourceZipFileFullPathName">要解壓縮的檔案路徑名稱</param>
/// <param name="password">解壓縮的密碼</param>
public static void DeCompressionToFileByPassword(string sourceZipFileFullPathName,string password)
{
      using (FileStream input = new FileStream(sourceZipFileFullPathName, FileMode.Open, FileAccess.Read))
      using (ZipInputStream zipIn = new ZipInputStream(input))
      {
           zipIn.Password = password;
           ZipEntry entry = zipIn.GetNextEntry();
           using (FileStream output = new FileStream(entry.Name, FileMode.Create, FileAccess.Write))
           {
                byte[] data = new byte[4096];
                int readLength = 0;
                while (true)
                {
                    readLength = zip.Read(data, 0, data.Length);
                    if (readLength > 0)
                        output.Write(data, 0, readLength);
                    else
                        break;
                }
           }
      }
}

 

對串流做壓縮與解壓縮

 


 

在某些情況下,我們會希望不要在寫檔或讀檔案才做壓縮與解壓縮,而是直接對串流做完壓縮後,可能送至某地方,在做解壓縮,例如Http資料傳輸等。

在此狀況下便需要直接對資料做壓縮與解壓縮了。

 

串流壓縮

先準備一份壓縮過後要存放的MemoryStream 物件,並把此MemoryStream 物件交由ZipOutputStream 存取,在做完壓縮後,把原始資料memStreamIn複製到此ZipOutputStream 後,在此實資料便會寫入在outputMemStream 其中,可以直接取用。


/// <summary>
/// 壓縮串流資料(不存檔)
/// </summary>
/// <param name="memStreamIn">來源資料串流</param>
/// <param name="zipEntryName">zip的名稱,這裡只需給個名稱不需給路徑</param>
/// <param name="password">壓縮密碼</param>
/// <returns>回傳已經壓縮的串流資料</returns>
public static MemoryStream CompressionToStreamByPassword(MemoryStream memStreamIn,string zipEntryName,string password)
{
            MemoryStream outputMemStream = new MemoryStream();
            ZipOutputStream zipStream = new ZipOutputStream(outputMemStream);
            zipStream.Password = password;
            ZipEntry newEntry = new ZipEntry(zipEntryName);
            newEntry.DateTime = DateTime.Now;

            zipStream.PutNextEntry(newEntry);

            StreamUtils.Copy(memStreamIn, zipStream, new byte[4096]);
            zipStream.CloseEntry();

            zipStream.IsStreamOwner = false;    // False stops the Close also Closing the underlying stream.
            zipStream.Close();          // Must finish the ZipOutputStream before using outputMemStream.
            // Alternative outputs:
            // ToArray is the cleaner and easiest to use correctly with the penalty of duplicating allocated memory.
            outputMemStream.Position = 0;
            return outputMemStream;

}

 

串流解壓縮

先把來源的已經壓縮串流zipMemStream 交由ZipInputStream 物件處理,並透過ZipEntry物件做解壓縮後,把此ZipInputStream 已經解壓縮的串流複製到要保存解壓縮串流的outputUnzipMemStream 物件


/// <summary>
/// 解壓縮串流
/// </summary>
/// <param name="zipMemStream">要解壓縮的來源串流</param>
/// <param name="password">解壓縮密碼</param>
/// <returns>解壓縮的原資料流</returns>
public static MemoryStream DeCompressionToStreamByPassword(MemoryStream zipMemStream,string password)
{
            MemoryStream outputUnzipMemStream = new MemoryStream();
            Console.WriteLine("ZipInutStream Size = " + zipMemStream.Length);
            ZipInputStream zipStream = new ZipInputStream(zipMemStream);
            zipStream.Password = password;
            //需要透過ZipEntry此類別才能對Zip Input/Output Stream作壓縮解壓縮動作
            ZipEntry entry = zipStream.GetNextEntry();
            StreamUtils.Copy(zipStream, outputUnzipMemStream, new byte[4096]);           
            return outputUnzipMemStream;
}

 

 

 

參考資料

SharpZipLib

Zip Samples

SharpZipLib create an archive with an in-memory string and download as an attachment

Zip Your Data Using the Zip Classes in the J# Class Libraries to Compress Files and Data with C#

 

 


 

文章中的敘述如有觀念不正確錯誤的部分,歡迎告知指正 謝謝 =)

另外要轉載請附上出處 感謝