C# Compression using DotNetZip(Ionic.Zip)
前言
DotNetZip 這個壓縮/解壓縮.zip檔的套件,使用上很簡潔直覺易懂
以下記錄此套件的使用方式
內文
using Ionic.Zip;//Nuget套件先找「DotNetZip」安裝後再引用此命名空間
using System;
using System.Collections.Generic;
using System.IO;
namespace MyWeb.Utility
{
public class MyFileHelper
{
/// <summary>
/// 將多個檔案打包成zip
/// </summary>
/// <param name="dFilePaths">Key為檔案總管完全路徑,Value為可讀性檔名</param>
/// <param name="zipPWD"></param>
/// <returns></returns>
public static byte[] CompressFilesToZipArchive(string zipFileName, Dictionary<string, string> dFilePaths, string zipPWD = null)
{
//回傳結果
byte[] file = null;
//要回傳的.zip檔案串流
using (MemoryStream ms = new MemoryStream())
{
//把多個檔案打包成一個.zip檔
using (ZipFile zip = new ZipFile())
{
//先設定編碼,避免壓縮檔裡的中文檔名為亂碼
zip.AlternateEncoding = System.Text.Encoding.UTF8;
zip.AlternateEncodingUsage = ZipOption.AsNecessary;
zip.Password = zipPWD;//zip上密碼,null值表示無密碼
zip.UseZip64WhenSaving = Zip64Option.AsNecessary;//避免壓縮大檔案出錯
//↓壓縮等級(視自己需求調整),沒寫就是預設值(平衡於壓縮速度和壓縮率)
//zip.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression;
//zipFileName當作zip檔內的目錄名稱
string folderNameInArchive = Path.GetFileNameWithoutExtension(zipFileName);
//將多筆檔案打包成.zip
foreach (KeyValuePair<string, string> entry in dFilePaths)
{
string sysfilePath = entry.Key;//來源檔案總管完全路徑
string zipEntryFileName = entry.Value;//在.zip檔內的可讀性檔名(不包含路徑)
#region 將sysFilePath轉成byte[]
FileStream fs = new FileStream(sysfilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
BinaryReader br = new BinaryReader(fs,System.Text.Encoding.UTF8);
//讀取來源檔案
byte[] sourceFile = br.ReadBytes(Convert.ToInt32(fs.Length));
br.Close();fs.Close();//關閉串流
#endregion
//把來源檔案放到.zip檔內指定的目錄下(留意zipEntryFileName若重覆檔名在zip內的同一目錄下,程式會報錯)
zip.AddEntry(Path.Combine(folderNameInArchive, zipEntryFileName), sourceFile);
}//end foreach
zip.Save(ms);//zip檔儲存在記憶體中
}//end using Zip
file = ms.ToArray();
}//end using MemoryStream
return file;
}//end method
/// <summary>
/// 解壓縮.zip檔
/// </summary>
/// <param name="zipFilePath"></param>
/// <param name="extractToDir"></param>
/// <param name="zipPWD"></param>
public static void DeCompressZip(string zipFilePath, string extractToDir, string zipPWD = null)
{
if (Directory.Exists(extractToDir) == false)//解壓目錄不存在
{
Directory.CreateDirectory(extractToDir);
}
//解壓縮全部
using (ZipFile zip = ZipFile.Read(zipFilePath))
{
zip.Password = zipPWD;//zip檔的解壓縮密碼,null值表示無密碼
zip.ExtractAll(extractToDir);//解壓縮到指定的目錄
}//end using
}//end method
/// <summary>
/// 輸出(下載)檔案給前端
/// </summary>
/// <param name="response"></param>
/// <param name="downloadFileName">下載檔名</param>
/// <param name="file">要下載的二進位檔案</param>
/// <param name="contentType">MIME-TYPE</param>
public static void DownloadFileToClient(System.Web.HttpResponse response, byte[] downloadFile, string downloadFileName, string contentType)
{
//準備下載(以下如果沒完整輸出,7-Zip軟體解壓縮時會發生錯誤)
response.Clear();
//跳出視窗,讓用戶端選擇要儲存的位置(使用 Uri.EscapeDataString() 編碼中文字才不會下載時,檔名為亂碼)
response.AddHeader("Content-Disposition", "attachment; filename=" + Uri.EscapeDataString(downloadFileName));//給User看的下載檔名
response.AddHeader("Content-Length", downloadFile.Length.ToString());
response.ContentType = contentType;
response.Flush();
response.BinaryWrite(downloadFile);//檔案輸出下載
response.End();
}
}//end class
}
前端叫用方式
using MyWeb.Utility;
using System;
using System.Collections.Generic;
namespace MyWeb
{
public partial class zipForm : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
/// <summary>
/// user點擊按鈕下載檔案
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void btnGo_Click(object sender, EventArgs e)
{
//要被打包壓縮的多個來源檔案路徑
Dictionary<string, string> sourceFilePaths = new Dictionary<string, string>();
/*
實務上Dictionary的Key值有可能是系統編碼過的檔名(為了存放在Server上檔名不重覆)
Value值為用戶上傳檔案的原始檔名
*/
sourceFilePaths.Add(Server.MapPath("~/zipTestFolder/中文檔名0001.jpg"), "中文檔名0001.jpg");
sourceFilePaths.Add(Server.MapPath("~/zipTestFolder/中文檔名0002.jpg"), "中文檔名0002.jpg");
string zipFileName = "壓縮檔名.zip";
try
{
//產出.zip二進位檔案
byte[] zip = MyFileHelper.CompressFilesToZipArchive(zipFileName, sourceFilePaths);
//輸出檔案給前端
MyFileHelper.DownloadFileToClient(Response, zip, zipFileName, "application/zip");
return;//流程不往下執行
}
catch (Exception ex)
{//發生錯誤
Response.Write(ex.ToString());
}
}//end btnGo_Click Event
}
}
補充
ASP.net WebForm 的 Response
輸出檔案,如果沒完整輸出,7-Zip軟體解壓縮時會發生以下錯誤:
「有效負載盡頭外還有其他資料」、「There are some data after the end of the payload data」
參考文章
官方說明文件:AddFile Method (fileName, directoryPathInArchive)