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

GZipStream 壓縮/解壓縮陷阱:小資料塊無法解壓縮的根因與解法

     編輯:關於C語言

問題現象

使用 GZipStream 壓縮網頁內容存儲,解壓縮時發現:壓縮後資料小於 4 KB 會導致解壓縮失敗,Read() 永遠回傳 0。

錯誤程式碼(缺少 Close/Dispose)

public static byte[] Compress(byte[] data)
{
    MemoryStream ms = new MemoryStream();
    GZipStream gzip = new GZipStream(ms, CompressionMode.Compress);
    gzip.Write(data, 0, data.Length);
    // 缺少 gzip.Close() 或 gzip.Dispose()
    return ms.ToArray(); // 資料尚未完全寫入 ms!
}

public static byte[] Decompress(byte[] data)
{
    MemoryStream ms = new MemoryStream();
    GZipStream gzip = new GZipStream(new MemoryStream(data), CompressionMode.Decompress);
    byte[] buffer = new byte[4096];
    int n;
    while ((n = gzip.Read(buffer, 0, buffer.Length)) != 0) // n 永遠為 0
        ms.Write(buffer, 0, n);
    return ms.ToArray();
}

根因分析

  • GZipStream 內部以 4 KB 為區塊緩衝。
  • 資料未滿 4 KB 時,資料停留在內部緩衝區,只有呼叫 Close() 或 Dispose() 才會將剩餘資料刷入底層串流。
  • 直接呼叫 ms.ToArray() 取得的是不完整的壓縮資料,導致解壓縮端無法識別 GZIP 標頭/尾部。

正確寫法

public static byte[] Compress(byte[] data)
{
    using (MemoryStream ms = new MemoryStream())
    using (GZipStream gzip = new GZipStream(ms, CompressionMode.Compress))
    {
        gzip.Write(data, 0, data.Length);
        // using 區塊結束自動呼叫 Dispose(),等同 Close()
    }
    return ms.ToArray(); // 此時資料已完整寫入
}

public static byte[] Decompress(byte[] data)
{
    using (MemoryStream ms = new MemoryStream())
    using (GZipStream gzip = new GZipStream(new MemoryStream(data), CompressionMode.Decompress))
    {
        gzip.CopyTo(ms); // .NET 4+ 可直接用 CopyTo,簡潔且高效
    }
    return ms.ToArray();
}

關鍵提醒

  1. 一定要在寫入結束後呼叫 Close()/Dispose() 再取底層串流資料,這對所有「包裝串流」(CryptoStream、DeflateStream 等)皆適用。
  2. 善用 using 區塊確保釋放,程式碼更簡潔、例外安全。
  3. .NET Core / .NET 5+ 可直接用 System.IO.Compression.BrotliStream 或 ZLibStream 獲得更高壓縮率。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved