C#文件压缩算法比较 C# GZip, Deflate, Brotli, Zstd如何选择和使用

2次阅读

zstd比gzip压缩率高5–15%、解压快2–4倍;brotli压缩略优但解压慢30–50%;deflate无crc校验,仅适用于明确需raw deflate的场景;.net中zstd需第三方库,brotli自2.1原生支持但默认非最优级别。

C#文件压缩算法比较 C# GZip, Deflate, Brotli, Zstd如何选择和使用

压缩率和速度差异到底有多大

实测下来,Zstd 在中等以上数据量(>10KB)时,通常比 GZip 多压 5–15%,解压快 2–4 倍;Brotli 压缩率略优于 Zstd(尤其文本),但解压慢 30–50%,且 .NET 原生支持直到 6.0 才稳定;Deflate(即 System.IO.Compression.DeflateStream)和 GZip 底层共享算法,只是少了头校验,压缩率几乎一样,但没 CRC 校验,出错难排查。

实际选型不能只看 benchmark:

  • GZip 兼容性最好,httplinux 工具链、旧服务都认它
  • Zstd 需要 NuGet 引入 ZstdNetK4os.Compression.Zstd,.NET 6+ 可用 System.IO.Compression.ZLibStream?不,那是错觉——.NET 官方至今没内置 Zstd
  • BrotliSystem.IO.Compression.BrotliStream 中已原生支持(.NET Core 2.1+),但默认压缩级别是 BrotliCompressionLevel.Fastest,不是最优

如何在 C# 中安全替换 GZipStream

直接把 GZipStream 换成 BrotliStreamZstdStream 很容易出错,主因是流生命周期和 flush 行为不一致。

关键注意事项:

  • 所有压缩流都必须显式调用 FlushFinalBlock()Dispose()(推荐后者),否则末尾数据可能丢失——GZipStream 尤其敏感
  • BrotliStreamLeaveOpen 参数默认为 false,而 GZipStream 默认是 true,不统一会导致外层 FileStream 被意外关闭
  • 不要用 using (var s = new BrotliStream(...)) { s.Write(...) } 然后接着读——压缩流不支持重入或 Seek,写完就得关,再读要另开新流
  • 如果要兼容老客户端,别用 Zstd:没有标准 MIME type,HTTP Content-Encoding 不识别 zstd

什么时候该用 DeflateStream 而不是 GZipStream

只有一种情况:你明确知道接收方只要原始 deflate 数据块,且不校验完整性——比如对接某些嵌入式协议、自定义二进制 rpc 框架,或者复用 zlib 的 raw deflate 格式。

常见误用场景:

  • 想“省点开销”换 DeflateStream 替代 GZipStream,结果传输中静默损坏,因为没 CRC 校验,错误无法发现
  • DeflateStream 输出喂给 gzip -d,失败——gzip 期待的是 RFC 1952 格式,而 DeflateStream 输出的是 RFC 1951 raw deflate
  • HTTP 响应设 Content-Encoding: deflate,但实际发的是 GZipStream 数据,浏览器会解不出——iis 和部分反向代理对这个 header 解析极严格

Zstd 在 .NET 中的落地难点

不是 API 复杂,而是生态断层:官方没内置,主流三方库又分两派——ZstdNet(基于 C# 纯实现,慢、内存高)和 K4os.Compression.Zstd(绑定原生 libzstd,快但需部署 .dll/.so/.dylib)。

上线前必须确认:

  • 目标服务器是否允许加载非托管 DLL?windows Server 默认策略可能拦截 zstd.dll
  • K4osZstdStream 默认不缓冲,小块写入性能差,建议包一层 BufferedStream
  • 它的 CompressionLevel 是 1–22,但 .NET 原生的 GZipStream 是 0–9,别直接映射——level 3 在 Zstd ≈ level 6 在 GZip
  • 没有 ZstdStream.CanSeek,也没有 position,别试图在压缩流里做随机访问

最常被忽略的一点:Zstd 的“单次压缩”接口(如 Zstd.Compress)适合小数据,但大文件流式压缩时,务必用 ZstdStream + 正确的 buffer size(建议 64KB 起),否则 GC 压力陡增。

text=ZqhQzanResources