上传文件
  1. base64hub
  2. 学习 Base64
  3. Base64 与其他编码
详解

Base64 与 Hex、Base32、Base58、Base85 对比

每种二进制转文本编码都要在体积、可读性和允许使用的字符集之间做取舍。下面用同一个输入演示其中九种,并列出它们的体积开销和字符集。

对比表

这些编码都能把任意字节无损地转成可打印文本,再转回来。区别在于用多少个字符、用哪些字符,以及输出会膨胀多少。

编码字母表输出体积区分大小写URL 安全典型用途
Hex(Base16)0-9 a-f200%否是哈希、MAC 地址、字节转储、颜色代码
Base32(RFC 4648)A-Z 2-7,填充 =160%否(规范要求大写)是,不带 = 时TOTP 密钥、Tor 洋葱地址、DNSSEC(base32hex)
Base58(比特币)1-9 A-Z a-z 去掉 0 O I l约 137%是是比特币地址、IPFS CIDv0(Qm…)、Solana 密钥
Base64A-Z a-z 0-9 + /,填充 =133%是否邮件附件、data URI、PEM、JSON 载荷
Base64URLA-Z a-z 0-9 - _133%是是JWT、URL 令牌、文件名
Ascii85! 到 u,外加 z125%是否PDF 和 PostScript 流
Z8585 个字符,含 .-:+=^!/*?&<>()[]{}@%$#125%是否ZeroMQ CURVE 密钥
Base45(RFC 9285)0-9 A-Z、空格、$%*+-./:150%否(仅大写)否二维码、欧盟数字新冠证书

“输出体积”指输入较大时,编码后长度占输入长度的比例。Base64 每 3 个字节需要 4 个字符,Base32 每 5 个字节需要 8 个,Base85 每 4 个字节需要 5 个,Base45 每 2 个字节需要 3 个。Base58 没有固定的分组大小,所以比例是 log(256) / log(58),约为 1.366。想知道某个具体输入的确切数字,体积计算器会一次性列出全部结果。

同一输入在各编码下的结果

下面是 12 字节的 ASCII 字符串 Hello world! 的九种编码。12 是 3 和 4 的倍数,所以 Base64 和 Base85 各变体都不需要填充。

编码输出长度
Hex48656c6c6f20776f726c642124
Base32JBSWY3DPEB3W64TMMQQQ====24(不带填充为 20)
Base32hex91IMOR3F41RMUSJCCGGG====24
Base58(比特币字母表)2NEpo7TZRhna7vSvL17
Base64SGVsbG8gd29ybGQh16
Base45%69 VD82EK4F.KESTC18
Ascii8587cURD]j7BEbo8015
Z85nm=QNzY<mxA+]nf15
Base85(RFC 1924 / git)NM&qnZy<MXa%^NF15

这里 Base64URL 和 Base64 完全相同,因为输出中没有 + 或 /。区别只在某些字节上才会显现:fb ef be 在 Base64 中是 ++++,在 Base64URL 中是 ----。

Python 标准库覆盖了表中的大部分编码,其中 z85encode 是 Python 3.13 新增的:

import base64

data = b"Hello world!"
print(data.hex())                           # 48656c6c6f20776f726c6421
print(base64.b32encode(data).decode())      # JBSWY3DPEB3W64TMMQQQ====
print(base64.b64encode(data).decode())      # SGVsbG8gd29ybGQh
print(base64.a85encode(data).decode())      # 87cURD]j7BEbo80
print(base64.b85encode(data).decode())      # NM&qnZy<MXa%^NF
print(base64.z85encode(data).decode())      # nm=QNzY<mxA+]nf

Base58 不在标准库里,但几行代码就能写出来,因为它只是对一个大整数做普通的进制转换:

B58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

def b58encode(data: bytes) -> str:
    n = int.from_bytes(data, "big")
    out = ""
    while n:
        n, r = divmod(n, 58)
        out = B58[r] + out
    zeros = len(data) - len(data.lstrip(b"\0"))
    return "1" * zeros + out

print(b58encode(b"Hello world!"))   # 2NEpo7TZRhna7vSvL
print(b58encode(b"\0\0\x01"))       # 112

每个开头的零字节都会变成字面上的 1,因为大整数无法记住前导零。这就是为什么所有版本字节为零的传统比特币地址都以 1 开头。

各编码的使用场景

Hex

Hex 每个字节用两个字符,是这里体积最大、也最容易阅读的选项。每个字符恰好对应 4 个比特,所以偏移量为 n 的字节总是位于第 2n 和 2n+1 个字符。正因如此,哈希、校验和与调试转储几乎都用 hex。解码器 DEADBEEF 和 deadbeef 都接受。可以用 Base64 转 hex 和 hex 转 Base64 进行转换。

Base32

Base32 只用大写字母和数字 2 到 7。它能在不区分大小写的系统中保持不变(DNS 名称、某些文件系统、在手机上手动输入验证码的人),还避开了容易和 O、I、B 混淆的 0、1、8。身份验证器应用用 Base32 存储 TOTP 密钥,Tor v3 洋葱地址是 56 个小写 Base32 字符。RFC 4648 还定义了 base32hex(0-9 A-V),它能保持原始字节的排序顺序。试试 Base32 编码器。

Base58

Base58 源自比特币。它去掉了容易混淆的 0、O、I、l,以及会破坏双击选中和 URL 的 +、/。比特币地址在此基础上加了一个版本字节和 4 字节校验和,这种格式叫做 Base58Check。IPFS CIDv0 哈希也是 Base58,由于它们以 multihash 字节 12 20 开头,所以总是以 Qm 开头。因为整个输入被当成一个数字处理,转换时间随长度呈平方增长,所以 Base58 用于密钥和哈希这类较短的值。试试 Base58 编码器。

Ascii85、Z85 和 git 的 Base85

Base85 家族把 4 个字节装进 5 个字符,是得到广泛支持的编码中最紧凑的。问题出在字母表上:85 个可打印字符意味着,视变体不同,会包含引号、反斜杠、<、> 或 &。

  • Ascii85(Adobe)使用 ! 到 u,输出用 <~ 和 ~> 包起来,四个零字节写成一个 z。PostScript 和 PDF(ASCII85Decode 过滤器)都在用它。
  • Z85(ZeroMQ)挑选的字符在 C 和 JSON 字符串字面量中都是安全的,不含引号和反斜杠。它要求输入长度是 4 的倍数。一个 32 字节的 CURVE 密钥是 40 个字符。
  • RFC 1924 Base85 原本是一个关于 IPv6 地址的愚人节提案。它的字母表在 git 二进制补丁和 Python 的 b85encode 中延续了下来。

Base85 工具支持全部三种,Z85 另有专门的页面。

Base45

Base45 是为二维码而生的。二维码的字母数字模式恰好能存储 45 个字符(数字、大写字母、空格和 $%*+-./:),每个字符占 5.5 比特,而字节模式下每个字符占 8 比特。Base45 把 2 个字节转成 3 个这样的字符,在二维码中的开销约为 3%。Base64 文本只能使用字节模式,开销为 33%。欧盟数字新冠证书正是出于这个原因使用了 Base45。试试 Base45 编码器。

如何选择

选接收方期望的编码。JWT 库要 Base64URL,身份验证器应用要 Base32,比特币钱包要 Base58Check。如果两端都由你控制,可以参考下面的经验法则:

  • JSON、XML、电子邮件或 HTTP 正文中的字节:Base64。每种语言都有快速的内置实现,33% 的开销可以接受。
  • 放在 URL、Cookie 或文件名中:不带填充的 Base64URL。
  • 需要人来阅读、输入或比对:短哈希用 hex;可能丢失大小写时用 Base32;希望看起来紧凑且没有易混淆字符时用 Base58。
  • 每个字节都很宝贵,且解码器由你控制:Z85 或 Ascii85。
  • 二维码:Base45。

取舍始终是同一个:字母表越大,输出越短,需要在某处转义的字符也越多。关于 Base64 为什么会膨胀三分之一,见 Base64 体积开销。关于 URL 安全的变体,见 Base64 与 Base64URL。

常见问题

哪种二进制转文本编码最紧凑?

常见编码中,Base85(Ascii85 和 Z85)开销为 25%,其次是 33% 的 Base64。basE91 还能再好一点,但支持它的地方很少。需要的话可以用 Base91 工具。

比特币为什么用 Base58 而不用 Base64?

Base58 去掉了 0、O、I、l、+ 和 /,所以地址更容易念出来、手抄,也能在文本框里双击整段选中。代价是要做较慢的大数转换,但对 25 字节的地址来说无关紧要。

Base32 和 Base58 区分大小写吗?

RFC 4648 的字母表是大写的,严格的解码器会拒绝小写。很多解码器两者都接受,Python 需要传入 casefold=True。Base58 区分大小写:a 和 A 是两个不同的数位。Hex 在几乎所有解码器中都不区分大小写。

Base64 能直接转成 Base58 或 Base32 吗?

可以,先解码成字节再重新编码即可。Base64 转 Base58 和 Base64 转 Base32 转换器会在你的浏览器本地完成这两步。

继续阅读