Base85 编码详解:比 Base64 更紧凑的二进制文本编码方案
全面了解 Base85(Ascii85)编码的工作原理、85 个字符的字母表、编解码算法、z 零压缩与 <~ ~> 分隔符,以及它在 PostScript、PDF、Git 等领域的广泛应用。
什么是 Base85?
Base85 是一种高效的二进制到文本编码方案,使用 85 个可打印 ASCII 字符来表示任意二进制数据。它最广为人知的变体是 Ascii85,由 Paul E. Rutter 于 1985 年为 btoa 工具开发,后被 Adobe 公司采纳并用于 PostScript 和 PDF 文件格式中,因此也常被称为 Adobe Ascii85。
Base85 的核心优势在于它比 Base64 拥有更高的编码效率——将 4 字节的二进制数据编码为 5 个字符,膨胀率仅为 25%,而 Base64 的膨胀率为 33.3%。这意味着在同样的数据量下,Base85 编码后的输出更短,在带宽和存储敏感的场景中具有明显优势。
在线工具推荐:需要进行 Base85 编码或解码?试试我们的在线 Base85 编解码工具,支持文本和十六进制输入、
<~ ~>分隔符、z 零压缩等多种选项。
Base85 字符表
Ascii85 使用从 ASCII 码 33(!)到 117(u)的连续 85 个可打印字符作为编码字母表:
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstu
每个字符对应的索引值为其 ASCII 码减去 33:
| 字符 | ASCII 码 | 索引值 |
|---|---|---|
! | 33 | 0 |
" | 34 | 1 |
# | 35 | 2 |
| … | … | … |
s | 115 | 82 |
t | 116 | 83 |
u | 117 | 84 |
设计理念:选择 ASCII 33-117 的范围是为了避免使用空格(32)和 DEL(127)等不可见/控制字符,同时利用尽可能多的可打印字符来最大化编码效率。
Base85 的工作原理
编码过程(4 字节 → 5 字符)
Base85 编码以 4 字节(32 位) 为一组进行处理:
- 读取 4 字节:将连续 4 个字节视为一个 32 位无符号整数(大端序)
- 进制转换:将该整数反复除以 85,取余数
- 字符映射:将每个余数加上 33 得到对应的 ASCII 字符
- 输出 5 字符:4 字节产生 5 个编码字符
数学基础:4 字节可表示的最大值为 2³² − 1 = 4,294,967,295,而 85⁵ = 4,437,053,125 > 4,294,967,295,所以 5 个 Base85 字符足以表示 4 个字节。
示例:编码字符串 “Man “(包含尾部空格)
字节: 0x4D 0x61 0x6E 0x20
整数值:1298230816(十进制)
1298230816 ÷ 85 = 15273303 余 61 → chr(61+33) = '^'
15273303 ÷ 85 = 179685 余 78 → chr(78+33) = 'o'
179685 ÷ 85 = 2113 余 80 → chr(80+33) = 'q'
2113 ÷ 85 = 24 余 73 → chr(73+33) = 'j'
24 ÷ 85 = 0 余 24 → chr(24+33) = '9'
逆序排列:9jqo^
尾部填充处理
当输入数据的字节数不是 4 的倍数时,需要在末尾补零字节凑齐 4 字节进行编码,然后丢弃多余的编码字符:
| 剩余字节数 | 补零数 | 编码字符数 | 输出字符数 |
|---|---|---|---|
| 1 | 3 | 5 | 2 |
| 2 | 2 | 5 | 3 |
| 3 | 1 | 5 | 4 |
解码时采用对称的策略:用 u(索引 84)填充至 5 字符,解码后丢弃多余字节。
解码过程(5 字符 → 4 字节)
解码是编码的逆操作:
- 读取 5 字符:将 5 个编码字符的索引值按 85 进制计算
- 还原整数:value = c₀ × 85⁴ + c₁ × 85³ + c₂ × 85² + c₃ × 85¹ + c₄ × 85⁰
- 拆分字节:将 32 位整数拆分为 4 个字节
特殊功能
<~ ~> 分隔符
Adobe 定义的 Ascii85 格式使用 <~ 和 ~> 作为编码数据的包裹标记,用于明确标识 Base85 编码区段的起止位置。这在 PostScript 和 PDF 文件中尤为重要,因为编码数据需要嵌入在其他格式的文本中。
原始数据:Hello
不带分隔符:87cURDZ
带分隔符: <~87cURDZ~>
z 零压缩
当一个完整的 4 字节组全部为零(即整数值为 0)时,Ascii85 可以用单个字符 z 来代替原本的 5 个编码字符 !!!!!。这种零压缩在处理包含大量零字节的数据(如图像的空白区域)时,能显著减小编码后的体积。
4 个零字节(00 00 00 00):
标准编码:!!!!!(5 个字符)
零压缩: z(1 个字符)
注意:
z压缩仅适用于完整的 4 字节组。对于尾部不足 4 字节的情况,不能使用零压缩。
空白字符处理
在实际应用中,Base85 编码的数据经常被格式化为多行显示(例如在 PostScript 文件中每行限制 80 个字符)。解码器通常会忽略编码数据中的空白字符(空格、制表符、换行符等),以正确处理换行和格式化。
编码效率对比
| 编码方案 | 输入 : 输出 | 膨胀率 | 字符集大小 |
|---|---|---|---|
| Base85 | 4 : 5 | 25% | 85 |
| Base64 | 3 : 4 | 33.3% | 64 |
| Base62 | 大整数运算 | ~37% | 62 |
| Base58 | 大整数运算 | ~37% | 58 |
| Base32 | 5 : 8 | 60% | 32 |
| Base16 (Hex) | 1 : 2 | 100% | 16 |
Base85 的主要变体
1. Ascii85(Adobe 变体)
- 字符集:ASCII 33-117(
!到u) - 分隔符:
<~ ~> - 零压缩:支持
z字符 - 用途:PostScript、PDF 文件格式
- 状态:最广泛使用的变体,也是我们工具实现的版本
2. Z85(ZeroMQ 变体)
- 字符集:
0-9a-zA-Z.-:+=^!/*?&<>()[]{}@%$#(重新排列的 85 个字符) - 分隔符:无
- 零压缩:不支持
- 用途:ZeroMQ 消息传输、网络协议
3. RFC 1924 变体(IPv6)
- 字符集:
0-9A-Za-z!#$%&()*+-;<=>?@^_{|}~ - 用途:提出用于 IPv6 地址的紧凑表示(愚人节 RFC,未广泛实施)
- 特点:128 位 IPv6 地址编码为 20 个字符
4. btoa 原始格式
- 字符集:与 Ascii85 相同
- 分隔符:
xbtoa Begin和xbtoa End - 特点:包含校验信息,是 Ascii85 的前身
常见应用场景
1. PostScript 和 PDF
Base85 最重要的应用是在 Adobe 的 PostScript 和 PDF 文件格式中。这些格式需要将二进制数据(如图像、字体、嵌入文件)编码为文本形式,Base85 比 Base16 和 Base64 都更紧凑,能有效减小文件体积。
2. Git 二进制补丁
Git 版本控制系统在生成二进制文件的补丁(binary diff/patch)时使用 Base85 编码。当执行 git diff 对二进制文件产生差异时,Git 使用 Base85 将差异数据编码为文本格式。
3. 数据序列化与传输
在需要通过纯文本通道传输二进制数据的场景中(如 JSON 嵌入、XML CDATA),Base85 比 Base64 节省约 6% 的空间。
4. 网络协议
ZeroMQ 使用 Z85 变体在消息中嵌入二进制数据,确保编码后的字符串在各种编程语言和传输协议中都能安全传递。
5. 嵌入式系统
在存储和带宽受限的嵌入式环境中,Base85 的 25% 膨胀率相比 Base64 的 33.3% 可以节省宝贵的存储空间和传输带宽。
Base85 与其他编码方案的比较
| 特性 | Base85 | Base64 | Base62 | Base58 | Base91 |
|---|---|---|---|---|---|
| 字符集大小 | 85 | 64 | 62 | 58 | 91 |
| 膨胀率 | 25% | 33.3% | ~37% | ~37% | ~14-23% |
| 编码单位 | 4→5 | 3→4 | 大整数 | 大整数 | 位流 |
| 包含特殊符号 | 是 | 是 | 否 | 否 | 是 |
| URL 安全 | ❌ | ❌ 需变体 | ✅ | ✅ | ❌ |
| 零压缩 | ✅ | ❌ | ❌ | ❌ | ❌ |
| 标准化 | Adobe 标准 | RFC 4648 | 无 | 无 | 无 |
| 主要用途 | PS/PDF/Git | 通用传输 | 短链接/ID | 加密货币 | 极致紧凑 |
实现注意事项
-
整数溢出:4 字节编码时涉及的最大值为 85⁵ − 1 = 4,437,053,124,在 JavaScript 的安全整数范围内,但在 C/C++ 等语言中需注意使用无符号 32 位整数。
-
z 字符位置:
z只能替代完整的 4 字节零组,不能出现在 5 字符组的中间。解码器在遇到z时应检查当前组是否为空。 -
非法字符检测:编码后的字符应在 ASCII 33-117 范围内(加上可选的
z)。解码器需要验证字符合法性。 -
分隔符处理:解码时需正确识别和去除
<~ ~>分隔符,同时支持有无分隔符的两种输入格式。 -
大文件处理:建议采用流式处理(以 4 字节为单位逐组编码),避免将整个文件加载到内存中。
Base85 的优缺点
优点
- 编码效率高:25% 膨胀率,在常用编码中仅次于 Base91
- 零压缩:对含大量零字节的数据可进一步压缩
- 工业标准:被 Adobe PostScript/PDF 和 Git 等广泛采用
- 固定比率:4:5 的固定编码比率使得输出长度易于预测
- 分隔符:
<~ ~>提供了清晰的边界标记
缺点
- 包含特殊字符:编码结果包含需要转义的字符
- 非 URL 安全:包含 URL 特殊字符,不能直接用于 URL
- 大小写敏感:在不区分大小写的环境中可能出问题
- 实现复杂度:比 Base64(纯位操作)更复杂,需要除法运算
- 变体众多:Ascii85、Z85、btoa 等变体的字符集不同,互不兼容
安全性考虑
-
Base85 不是加密:与所有编码方案一样,Base85 只是数据表示方式,不提供保密性。敏感数据必须先加密再编码。
-
注入风险:Base85 编码结果包含
<、>、"等特殊字符,直接嵌入 HTML、XML 或 SQL 中可能导致注入攻击,应进行适当转义。 -
数据完整性:标准 Ascii85 不包含内置校验和。如需确保数据完整性,应在应用层添加 CRC 或哈希校验。
如何选择合适的编码?
- 需要最高编码效率且允许特殊字符:选择 Base85 或 Base91
- 需要通用兼容性和广泛支持:选择 Base64(RFC 标准)
- 需要 URL 安全:选择 Base62 或 Base58
- 需要嵌入 PostScript/PDF:选择 Base85 (Ascii85)
- 需要人工输入不易出错:选择 Base58(无混淆字符)
总结
Base85(Ascii85)是一种高效、成熟的二进制文本编码方案。它以 25% 的低膨胀率在编码效率上显著优于 Base64,同时提供了 z 零压缩和 <~ ~> 分隔符等实用特性。从 Adobe PostScript/PDF 到 Git 二进制补丁,Base85 在需要紧凑文本表示的场景中发挥着重要作用。
如果你正在处理 PDF 生成、Git 补丁解析,或任何需要高效二进制文本编码的场景,Base85 都是一个值得优先考虑的方案。赶快使用我们的 Base85 编解码工具 来亲身体验吧!