在實際項目開發中,文件壓縮與解壓是極為常見的需求——無論是為了減少網絡傳輸帶寬,還是方便用戶批量下載資源。雖然 .NET Framework 4.5+ 內建了 ZipArchive 類,但在相容性、功能豐富度與加密支持上,第三方庫 ICSharpCode.SharpZipLib 依然是眾多開發者的首選。本文將分享一個經過項目實戰驗證的 ZipHelper 封裝類,涵蓋單文件、單目錄、多文件/目錄混合壓縮、加密壓縮與解壓等核心場景,代碼開箱即用。
ZipFilepublic void ZipFile(string filePath, string zipedFileName, int compressionLevel = 9)
{
// 參數校驗、自動補全 .zip 後綴、創建目標目錄...
using (var streamToZip = new FileStream(filePath, FileMode.Open, FileAccess.Read))
using (var zipFile = File.Create(zipedFileName))
using (var zipStream = new ZipOutputStream(zipFile))
{
var zipEntry = new ZipEntry(Path.GetFileName(filePath));
zipStream.PutNextEntry(zipEntry);
zipStream.SetLevel(compressionLevel);
var buffer = new byte[2048];
int size = streamToZip.Read(buffer, 0, buffer.Length);
zipStream.Write(buffer, 0, size);
while (size < streamToZip.Length)
{
int sizeRead = streamToZip.Read(buffer, 0, buffer.Length);
zipStream.Write(buffer, 0, sizeRead);
size += sizeRead;
}
}
}
亮點:流式讀寫避免大文件佔用過多內存;compressionLevel 參數讓開發者可根據場景權衡壓縮率與耗時。
ZipDirpublic void ZipDir(string dirToZip, string zipedFileName, int compressionLevel = 9)
{
using (var zipOutputStream = new ZipOutputStream(File.Create(zipedFileName)))
{
zipOutputStream.SetLevel(compressionLevel);
var crc = new Crc32();
var fileList = GetAllFiles(dirToZip); // 遞歸收集所有文件路徑與修改時間
foreach (DictionaryEntry item in fileList)
{
using (var fs = new FileStream(item.Key.ToString(), FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
var buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
var entry = new ZipEntry(Path.GetFileName(item.Key.ToString()))
{
DateTime = (DateTime)item.Value,
Size = fs.Length
};
crc.Reset();
crc.Update(buffer);
entry.Crc = crc.Value;
zipOutputStream.PutNextEntry(entry);
zipOutputStream.Write(buffer, 0, buffer.Length);
}
}
}
}
輔助方法 GetAllFiles / GetAllDirFiles / GetAllDirsFiles 以 Hashtable 返回「文件全路徑 → 最後修改時間」映射,確保壓縮包保留原始時間戳。
ZipManyFilesOrDictoryspublic bool ZipManyFilesOrDictorys(IEnumerable<string> folderOrFileList, string zipedFile, string passWord)
{
using (var s = new ZipOutputStream(File.Create(zipedFile)))
{
s.SetLevel(6); // 預設中等壓縮
if (!string.IsNullOrEmpty(passWord)) s.Password = passWord;
foreach (var fileOrDir in folderOrFileList)
{
if (Directory.Exists(fileOrDir))
ZipFileDictory(fileOrDir, s, "");
else
ZipFileWithStream(fileOrDir, s);
}
s.Finish();
return true;
}
}
內部私有方法 ZipFileDictory(遞歸處理子目錄)與 ZipFileWithStream(單文件流式寫入)協同工作,並在 finally 塊中顯式調用 GC.Collect() 釋放大文件句柄,體現工程化細節。
UnZippublic void UnZip(string zipFilePath, string unZipDir)
{
if (string.IsNullOrEmpty(unZipDir))
unZipDir = zipFilePath.Replace(Path.GetFileName(zipFilePath), Path.GetFileNameWithoutExtension(zipFilePath)) + "/";
using (var s = new ZipInputStream(File.OpenRead(zipFilePath)))
{
ZipEntry theEntry;
while ((theEntry = s.GetNextEntry()) != null)
{
var directoryName = Path.GetDirectoryName(theEntry.Name);
var fileName = Path.GetFileName(theEntry.Name);
if (!string.IsNullOrEmpty(directoryName))
Directory.CreateDirectory(unZipDir + directoryName);
if (!string.IsNullOrEmpty(fileName))
{
using (var streamWriter = File.Create(unZipDir + theEntry.Name))
{
var data = new byte[2048];
int size;
while ((size = s.Read(data, 0, data.Length)) > 0)
streamWriter.Write(data, 0, size);
}
}
}
}
}
自動處理目錄結構還原、空目錄創建,並以 2KB 緩衝區流式寫入,適合大型壓縮包。
ZipHelper 類位於命名空間 ZTO.PicTest.UtilitIEs,依賴 ICSharpCode.SharpZipLib.Checksums 與 ICSharpCode.SharpZipLib.Zip。類中包含:
ZipFile(兩個重載)、ZipDir、ZipManyFilesOrDictorys、UnZipGetAllFiles、GetAllDirFiles、GetAllDirsFiles、ZipFileWithStream、ZipFileDictorySharpZipLib(Install-Package SharpZipLib),避免手動引用 DLL 版本衝突。async/await 模式,避免阻塞線程。IProgress<double> 參數,實時反饋壓縮/解壓進度。ZipEntry.IsUnicodeText = true。本文提供的 ZipHelper 封裝了 SharpZipLib 最常用的壓縮解壓功能,代碼結構清晰、異常處理完善、支持加密與多源混合打包,可直接集成至項目中。掌握其核心流式處理與遞歸目錄遍歷邏輯,有助於在面對更複雜的文件打包需求時靈活擴展。持續積累此類通用工具類,將顯著提升開發效率——點滴積累,開心編程!