使用 GZipStream 壓縮網頁內容存儲,解壓縮時發現:壓縮後資料小於 4 KB 會導致解壓縮失敗,Read() 永遠回傳 0。
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 為區塊緩衝。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();
}
Close()/Dispose() 再取底層串流資料,這對所有「包裝串流」(CryptoStream、DeflateStream 等)皆適用。using 區塊確保釋放,程式碼更簡潔、例外安全。System.IO.Compression.BrotliStream 或 ZLibStream 獲得更高壓縮率。