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

压缩率和速度差异到底有多大
实测下来,Zstd 在中等以上数据量(>10KB)时,通常比 GZip 多压 5–15%,解压快 2–4 倍;Brotli 压缩率略优于 Zstd(尤其文本),但解压慢 30–50%,且 .NET 原生支持直到 6.0 才稳定;Deflate(即 System.IO.Compression.DeflateStream)和 GZip 底层共享算法,只是少了头校验,压缩率几乎一样,但没 CRC 校验,出错难排查。
实际选型不能只看 benchmark:
-
GZip兼容性最好,HTTP、Linux 工具链、旧服务都认它 -
Zstd需要 NuGet 引入ZstdNet或K4os.Compression.Zstd,.NET 6+ 可用System.IO.Compression.ZLibStream?不,那是错觉——.NET 官方至今没内置 Zstd -
Brotli在System.IO.Compression.BrotliStream中已原生支持(.NET Core 2.1+),但默认压缩级别是BrotliCompressionLevel.Fastest,不是最优
如何在 C# 中安全替换 GZipStream
直接把 GZipStream 换成 BrotliStream 或 ZstdStream 很容易出错,主因是流生命周期和 flush 行为不一致。
关键注意事项:
- 所有压缩流都必须显式调用
FlushFinalBlock()或Dispose()(推荐后者),否则末尾数据可能丢失——GZipStream尤其敏感 -
BrotliStream的LeaveOpen参数默认为false,而GZipStream默认是true,不统一会导致外层FileStream被意外关闭 - 不要用
using (var s = new BrotliStream(...)) { s.Write(...) }然后接着读——压缩流不支持重入或 Seek,写完就得关,再读要另开新流 - 如果要兼容老客户端,别用
Zstd:没有标准 MIME type,HTTPContent-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 -
K4os的ZstdStream默认不缓冲,小块写入性能差,建议包一层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 压力陡增。










