如何用 zlib 压缩并编码为 Base64
- 输入或粘贴文本,或者拖入一个文件。
- 格式 默认是 zlib (deflate)。接收方需要裸数据流时切换为 原始 deflate,也可以切换为 gzip。
- 可选勾选 URL 安全(- _) 或 每 76 字符换行。
- 点击 复制输出,或者下载 Base64 的
.txt,或二进制的.zz/.deflate文件。
互换 会把输出送到 解压 一侧,确认往返转换无误。
同一段文本,三种封装
Hello, world!(13 字节),以默认级别压缩:
| 格式 | 字节数 | Base64 |
|---|---|---|
| 原始 deflate | 15 | 80jNycnXUSjPL8pJUQQA |
| zlib | 21 | eJzzSM3JyddRKM8vyklRBAAgXgSK |
| gzip | 33 | H4sIAAAAAAAAA/NIzcnJ11Eozy/KSVEEAObG5usNAAAA |
三者中的 deflate 数据流都是同样的 15 个字节,但 Base64 看起来不同,因为 2 字节和 10 字节的头部改变了每个字节在 3 字节组中的位置。zlib 在默认级别下的头部是 78 9C,所以 zlib 的 Base64 以 eJ 开头。在级别 9 时头部是 78 DA,Base64 为 eN。
哪个函数生成哪种格式
大多数“deflate” bug 都源于双方用同一个词指代不同的封装:
| 语言 | zlib(RFC 1950) | 原始 deflate(RFC 1951) | gzip |
|---|---|---|---|
| Python | zlib.compress() | zlib.compressobj(wbits=-15) | gzip.compress() |
| Node.js | zlib.deflateSync() | zlib.deflateRawSync() | zlib.gzipSync() |
| 浏览器 | CompressionStream("deflate") | CompressionStream("deflate-raw") | CompressionStream("gzip") |
| PHP | gzcompress() | gzdeflate() | gzencode() |
| Java | new Deflater() | new Deflater(level, true) | GZIPOutputStream |
| .NET | ZLibStream(.NET 6+) | DeflateStream | GZipStream |
| Go | compress/zlib | compress/flate | compress/gzip |
注意其中的陷阱:.NET 的 DeflateStream 和 Go 的 compress/flate 是原始格式,而 Node 和浏览器的“deflate”是 zlib。一个 C# 服务和一个 Node 客户端都说自己“用 deflate”,但如果不改其中一方,它们彼此是读不懂的。
各种封装出现在哪里
- zlib:PDF 的
FlateDecode数据流、PNG 图像数据、Git 对象、许多二进制协议和游戏存档格式。 - 原始 deflate:SAML HTTP-Redirect 绑定(SAML 解码器 可以处理)、ZIP 文件中的条目、WebSocket 的
permessage-deflate。 - gzip:文件、HTTP、日志。详见 gzip 页面。
在代码中使用 zlib + Base64
import base64, zlib
packed = base64.b64encode(zlib.compress(b"Hello, world!")).decode()
# 'eJzzSM3JyddRKM8vyklRBAAgXgSK'
text = zlib.decompress(base64.b64decode(packed))
// Node.js: raw deflate for a SAML-style payload
const zlib = require("zlib");
const packed = zlib.deflateRawSync(Buffer.from("Hello, world!")).toString("base64");
// '80jNycnXUSjPL8pJUQQA'
要把这类字符串读回来,请使用 Base64 gzip 和 zlib 解码器,它能识别全部三种封装。更多内容见 Python 和 Node.js。
常见问题
incorrect header check:用 zlib 解码器处理了原始 deflate 或 gzip 数据。请匹配封装格式。invalid stored block lengths或invalid block type:用原始 deflate 解码器处理了 zlib 数据;两个头部字节被当成了 deflate 块来读取。- 结果比输入还长:短字符串压缩不了。大约 50–100 字节以下时,纯 Base64 更短。
- 输出与另一个工具的结果不能逐字节对上:压缩级别和所用的库都会改变字节,而任何正确的解压器都能从两者还原出相同的原文。
常见问题
zlib 和 deflate 有什么区别?
deflate 是压缩算法。原始 deflate 是裸的压缩数据流;zlib 在它外面加了 2 字节的头部和 4 字节的 Adler-32 校验和;gzip 加了 10 字节的头部和带 CRC-32 的 8 字节尾部。中间的压缩数据完全相同。
'incorrect header check' 是什么原因?
解压器期望的是 zlib 头部,得到的却是别的东西,最常见的是原始 deflate 或 gzip。请使用对应的函数(Python 中解压原始 deflate 用 zlib.decompress(data, -15)),或者按接收方期望的格式重新编码。
HTTP 的 Content-Encoding: deflate 是原始 deflate 还是 zlib?
HTTP 规范规定是 zlib。一些老服务器以这个名字发送原始 deflate,所以在 HTTP 中用 gzip 更稳妥。