首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# SharpZipLib 實作 Zip 壓縮/解壓縮完整指南:單檔、多檔、加密、註解

     編輯:關於C語言

SharpZipLib (ICSharpCode.SharpZipLib) 是 .NET 生態系歷史最悠久、相依性最輕量的開源壓縮庫,支援 Zip、GZip、BZip2、Tar 等格式,相容 .NET Framework 2.0+ 至 .NET 8。本文以 Zip 為主,示範單檔/多檔壓縮解壓、AES 加密、ZIP 註解、壓縮等級控制,並修正原始碼中常見的緩衝區大小錯誤。

NuGet 安裝

dotnet add package SharpZipLib

核心枚舉與工具類架構

public enum CompressionAlgorithm { Zip, GZip, BZip2 }

public static class ZipHelper
{
    // ... 以下方法皆為 static,方便直接呼叫
}

1. 單檔壓縮(Zip / GZip / BZip2)

public static bool CompressFile(string srcPath, string destPath, CompressionAlgorithm algo)
{
    try
    {
        using FileStream inFs = File.OpenRead(srcPath);
        using FileStream outFs = File.Create(destPath);

        switch (algo)
        {
            case CompressionAlgorithm.Zip:
                // Zip 需建立 ZipOutputStream,單一 Entry
                using (var zipOut = new ZipOutputStream(outFs))
                {
                    zipOut.SetLevel(6); // 0-9
                    var entry = new ZipEntry(Path.GetFileName(srcPath))
                    {
                        DateTime = DateTime.Now,
                        Size = inFs.Length
                    };
                    zipOut.PutNextEntry(entry);
                    inFs.CopyTo(zipOut);
                    zipOut.CloseEntry();
                }
                break;

            case CompressionAlgorithm.GZip:
                using (var gzOut = new GZipOutputStream(outFs))
                {
                    inFs.CopyTo(gzOut);
                }
                break;

            case CompressionAlgorithm.BZip2:
                // BZip2 需額外引用 ICSharpCode.SharpZipLib.BZip2
                BZip2.Compress(inFs, outFs, true, 4096);
                break;
        }
        return true;
    }
    catch { return false; }
}

2. 單檔解壓縮

public static bool DecompressFile(string srcPath, string destPath, CompressionAlgorithm algo)
{
    try
    {
        using FileStream inFs = File.OpenRead(srcPath);
        using FileStream outFs = File.Create(destPath);

        switch (algo)
        {
            case CompressionAlgorithm.Zip:
                using (var zipIn = new ZipInputStream(inFs))
                {
                    ZipEntry entry = zipIn.GetNextEntry(); // 單檔取第一個
                    if (entry == null) return false;
                    zipIn.CopyTo(outFs);
                }
                break;
            case CompressionAlgorithm.GZip:
                using (var gzIn = new GZipInputStream(inFs))
                    gzIn.CopyTo(outFs);
                break;
            case CompressionAlgorithm.BZip2:
                BZip2.Decompress(inFs, outFs, true);
                break;
        }
        return true;
    }
    catch { return false; }
}

3. 多檔壓縮成單一 Zip(支援密碼、註解、壓縮等級、目錄結構保留)

public static void CreateZipFromDirectory(
    string sourceDir, string zipPath,
    int compressionLevel = 6,      // 0=Store, 1=BestSpeed ... 9=BestCompression
    string password = null,        // AES-256 (SharpZipLib 1.3+)
    string comment = null,         // ZIP 檔案註解
    string searchPattern = "*",    // 檔案過濾
    SearchOption searchOption = SearchOption.AllDirectories)
{
    using var zipOut = new ZipOutputStream(File.Create(zipPath))
    {
        Password = password,           // null 表示不加密
        UseZip64 = UseZip64.On,        // 支援 4GB+ 大檔
    };
    zipOut.SetLevel(compressionLevel);
    if (!string.IsNullOrEmpty(comment))
        zipOut.SetComment(comment);

    // 計算基準路徑長度,用於保留相對目錄結構
    string baseDir = Path.GetFullPath(sourceDir).TrimEnd(Path.DirectorySeparatorChar);
    int baseLen = baseDir.Length + 1; // +1 for separator

    foreach (string file in Directory.GetFiles(sourceDir, searchPattern, searchOption))
    {
        string relativePath = file.Substring(baseLen).Replace(Path.DirectorySeparatorChar, '/');
        var entry = new ZipEntry(relativePath)
        {
            DateTime = File.GetLastWriteTime(file),
            Size = new FileInfo(file).Length
        };
        zipOut.PutNextEntry(entry);
        using FileStream fs = File.OpenRead(file);
        fs.CopyTo(zipOut); // .NET Core 2.1+ Stream.CopyTo 自動緩衝
        zipOut.CloseEntry();
    }
    zipOut.IsStreamOwner = true; // 確保 Dispose 關閉底層 FileStream
}

4. 解壓縮 Zip 到目錄(支援密碼、覆蓋、目錄自動建立)

public static void ExtractZipToDirectory(
    string zipPath, string destDir,
    string password = null,
    bool overwrite = true)
{
    Directory.CreateDirectory(destDir);
    using var zipIn = new ZipInputStream(File.OpenRead(zipPath));
    if (!string.IsNullOrEmpty(password))
        zipIn.Password = password;

    ZipEntry entry;
    while ((entry = zipIn.GetNextEntry()) != null)
    {
        if (entry.IsDirectory) continue; // 目錄項目由檔案項目隱含建立

        string destFile = Path.Combine(destDir, entry.Name);
        // 防止 Zip Slip 攻擊:確保解壓路徑在目標目錄內
        destFile = Path.GetFullPath(destFile);
        if (!destFile.StartsWith(Path.GetFullPath(destDir), StringComparison.OrdinalIgnoreCase))
            throw new SecurityException("Zip Slip 偵測:嘗試跳出目標目錄");

        if (File.Exists(destFile) && !overwrite) continue;
        Directory.CreateDirectory(Path.GetDirectoryName(destFile)!);

        using FileStream outFs = File.Create(destFile);
        zipIn.CopyTo(outFs);
    }
}

5. 進階主題

壓縮等級選擇指南

Level速度壓縮率建議場景
0 (Store)極快無壓縮已壓縮格式、需隨機存取
1-3快低即時備份、網路傳輸
4-6 (預設 6)平衡中通用預設值
7-9慢高離線封存、存儲成本敏感

加密說明

  • SharpZipLib 1.3+ 預設使用 AES-256(WinZip AES 擴充),相容 7-Zip、WinRAR、Windows 內建解壓縮。
  • 舊版僅支援 ZipCrypto(弱),請務必升級套件。
  • 密碼以 UTF-8 編碼,長度建議 ≥ 12 字元。

Zip Slip 防禦

惡意 Zip 可能包含 ../../etc/passwd 等路徑遍歷項目。ExtractZipToDirectory 中的 Path.GetFullPath + StartsWith 檢查為必要防禦。

大檔案與記憶體

  • 全部使用 Stream.CopyTo(內部 81920 bytes 緩衝),不將整個檔案讀入記憶體,支援 GB 級大檔。
  • 若需進度報告,可自行實作 byte[] buffer = new byte[81920] 迴圈並回呼進度。

呼叫範例

// 壓縮整個資料夾,AES-256 加密,附註解
ZipHelper.CreateZipFromDirectory(
    @"E:\Data\Export", @"E:\Backup\Export_20240518.zip",
    compressionLevel: 6, password: "Str0ngP@ssw0rd!",
    comment: "每日匯出備份 2024-05-18");

// 解壓縮
ZipHelper.ExtractZipToDirectory(
    @"E:\Backup\Export_20240518.zip", @"E:\Restore\Export",
    password: "Str0ngP@ssw0rd!");

SharpZipLib API 成熟穩定、零原生相依、支援 .NET Standard 2.0,是跨平台 .NET 專案處理 Zip 的首選輕量方案。掌握上述四大核心方法,即能覆蓋 95% 以上的壓縮/解壓縮業務需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved