做壓縮與解壓縮對現在來說,是滿普遍的需求,特別是在傳送大資料時,未了減少傳送的時間,所以也會先壓縮過資料再來傳送,而在.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上也可以直接安裝,而這邊我是使用下載的方式,解壓縮後會有三個資料夾,如下:
選擇其中一個參考以後,加入
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 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#
文章中的敘述如有觀念不正確錯誤的部分,歡迎告知指正 謝謝 =)
另外要轉載請附上出處 感謝