ICSharpCode.SharpZipLib (簡稱 SharpZipLib) 是 .NET 經典開源壓縮庫,支援 Zip、GZip、BZip2、Tar 等格式,純 C# 實作、無外部相依、相容 .NET Framework / .NET Core / .NET 5+。NuGet 安裝:Install-Package SharpZipLib。
ZipOutputStream:建立 Zip 檔案串流 (寫入)ZipInputStream:讀取 Zip 檔案串流 (解壓)ZipEntry:代表壓縮包內單一檔案/目錄項目FastZip:高階封裝,一行完成目錄壓縮/解壓using ICSharpCode.SharpZipLib.Zip;
using System.IO;
public void CompressFiles(List files, string zipPath, int compressionLevel = 9)
{
using (var zipStream = new ZipOutputStream(File.Create(zipPath)))
{
zipStream.SetLevel(compressionLevel); // 0=存儲, 9=最大壓縮
foreach (var file in files)
{
using (var fs = file.OpenRead())
{
var entry = new ZipEntry(file.Name) { DateTime = file.LastWriteTime };
zipStream.PutNextEntry(entry);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
zipStream.Write(buffer, 0, bytesRead);
}
}
zipStream.Finish(); // 必須呼叫 Finish() 寫入中央目錄
}
}
public void CompressDirectory(string sourceDir, string zipPath, int level = 9, bool deleteSource = false)
{
if (!Directory.Exists(sourceDir)) throw new DirectoryNotFoundException(sourceDir);
var files = GetAllFiles(sourceDir); // 遞迴取得所有檔案絕對路徑
using (var zipStream = new ZipOutputStream(File.Create(zipPath)))
{
zipStream.SetLevel(level);
foreach (var filePath in files)
{
// 計算相對路徑做為 Zip 內部路徑
string relativePath = filePath.Substring(sourceDir.Length).TrimStart('\\', '/');
var entry = new ZipEntry(relativePath)
{
DateTime = File.GetLastWriteTime(filePath),
Size = new FileInfo(filePath).Length
};
using (var fs = File.OpenRead(filePath))
{
zipStream.PutNextEntry(entry);
byte[] buffer = new byte[4096];
int read;
while ((read = fs.Read(buffer, 0, buffer.Length)) > 0)
zipStream.Write(buffer, 0, read);
}
}
zipStream.Finish();
}
if (deleteSource) Directory.Delete(sourceDir, true);
}
private List GetAllFiles(string dir)
{
var list = new List();
foreach (var file in Directory.GetFiles(dir)) list.Add(file);
foreach (var subDir in Directory.GetDirectories(dir)) list.AddRange(GetAllFiles(subDir));
return list;
}
public void DecompressZip(string zipPath, string targetDir)
{
if (!Directory.Exists(targetDir)) Directory.CreateDirectory(targetDir);
using (var zipStream = new ZipInputStream(File.OpenRead(zipPath)))
{
ZipEntry entry;
while ((entry = zipStream.GetNextEntry()) != null)
{
string fullPath = Path.Combine(targetDir, entry.Name);
if (entry.IsDirectory)
{
Directory.CreateDirectory(fullPath);
continue;
}
// 確保父目錄存在
string dir = Path.GetDirectoryName(fullPath);
if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
Directory.CreateDirectory(dir);
using (var fs = File.Create(fullPath))
{
byte[] buffer = new byte[4096];
int read;
while ((read = zipStream.Read(buffer, 0, buffer.Length)) > 0)
fs.Write(buffer, 0, read);
}
// 保留檔案時間
File.SetLastWriteTime(fullPath, entry.DateTime);
}
}
}
using ICSharpCode.SharpZipLib.Zip;
var fastZip = new FastZip();
// 建立密碼保護 Zip
fastZip.CreateZip(@"C:\Output\Protected.zip", @"C:\SourceDir", true, "password");
// 解壓
fastZip.ExtractZip(@"C:\Output\Protected.zip", @"C:\ExtractDir", "password");
Parallel.ForEach 平行壓縮多個 Zip。| 問題 | 解決 |
|---|---|
| 中文檔名亂碼 | SharpZipLib 1.3+ 預設 UTF-8,舊版需 zipStream.UseZip64 = UseZip64.Off; entry.Name = Encoding.UTF8.GetString(Encoding.GetEncoding(950).GetBytes(name)) 等 hack,建議升級新版。 |
| 解壓後檔案 0 位元組 | 忘記呼叫 zipStream.Finish() 或 entry.Size 未設定導致中央目錄不正確。 |
| 權限拒絕 | 檔案被佔用、目標目錄唯讀、壓縮包需管理員權限寫入。 |
原文連結:https://www.bianceng.cn/Programming/csharp/201410/45594.htm