.Net Deflate 压缩与 zlib 的差异
周末需要用 C# 访问某网站接口,解析返回数据时发现有些不对,DeflateStream
解不开 zlib
压缩返回来的数据!略一搜索之下发现是个陈年老坑了。
三种格式
这里一共有三种格式,分别是:
- RFC 1951
Raw Deflate
- RFC 1950
Raw Deflate
wrapped inzlib header
andzlib trailer
- RFC 1952
Raw Deflate
wrapped inGzip header
andGzip trailer
System.IO.Compression.DeflateStream
读写的格式被称为 Raw Deflate
,虽然同样调用 zlib
库生成,但不包括任何头尾部分。
根据 RFC 1950,zlib header
的定义如下:
0 1
+---+---+
|CMF|FLG| (-->)
+---+---+
CMF:
bits 0 to 3 CM Compression method
bits 4 to 7 CINFO Compression info
FLG:
bits 0 to 4 FCHECK (check bits for CMF and FLG)
bit 5 FDICT (preset dictionary)
bits 6 to 7 FLEVEL (compression level)
常见的几种组合:
78 01 - No Compression/low
78 9C - Default Compression
78 DA - Best Compression
其中 78 9C
尤为常见。
解决方案
1. 解压缩、格式固定
这也是我这次遇到的场景。
远端服务器(目测是 nodejs
)提供 JSON
序列化的内容,其中一个字段是 binary string
,处理之后得到一个 zlib
压缩的字节序列。
这种情况下,直接 Skip(2)
再丢给 DeflateStream
解压就可以了,毕竟官方库的性能是最好的。
2. 解压缩、算法固定、格式兼容
建议放弃官方库,使用 SharpZipLib
等第三方库。
3. 纯压缩、提供给前端下载
建议考虑其他压缩格式,如 Zip
等。
4. 纯压缩、与其他服务器交互
建议优先约定 Raw Deflate
,无法协商一致或对端要求 RFC 1950
或 RFC 1952
,可以在以下两种方式中二选一:
- 自己造轮子,补足对应的
header
和trailer
- 使用
SharpZipLib
等第三方库
如果考虑性能,可能自行补完头尾更合适一些,具体方式可以参考 RFC。