三种编码格式的本质
二进制数据无法直接以文本形式传输或显示,需要通过**编码(Encoding)**将字节序列映射为可打印 ASCII 字符。Base64、Base32 与 Hex 是三种最主流的二进制→文本编码方案,它们的本质区别只有一个:每个字符承载多少位。
| 编码 | 每字符位数 | 字符集大小 | 字符集范围 | 膨胀率 |
|---|---|---|---|---|
| Hex | 4 位 | 16 | 0-9A-F | 100% |
| Base32 | 5 位 | 32 | A-Z2-7(RFC 4648)或 0-9A-Z 去 I/L/O/U(Crockford) | 60% |
| Base64 | 6 位 | 64 | A-Za-z0-9+/ | 33% |
每字符承载的位数越多,编码后体积越小,但字符集更大、可读性更差。这是一条基础权衡曲线:体积 ↔ 可读性。
Hex:最直观的编码
工作原理
Hex(十六进制)将每个字节(8 位)拆分为两个 4 位段,分别映射到 0-9A-F 共 16 个字符。例如字节 0x48(即字符 H 的 ASCII)编码为字符串 "48"。
字节: H e l l o
Hex: 48 65 6c 6c 6f
5 种输出格式
Hex 编码虽简单,但实际使用中有 5 种主流输出格式:
- 连续:
48656c6c6f— 最紧凑,适合传输 - 空格分隔:
48 65 6c 6c 6f— 易读,常用于调试输出 - 0x 前缀:
0x48 0x65 0x6c 0x6c 0x6f— C/C++/Rust 字面量风格 - C 数组:
{ 0x48, 0x65, 0x6c, 0x6c, 0x6f }— 嵌入式固件字节数组 - Hex dump(xxd 风格):每行 16 字节,含偏移量、hex 部分、ASCII 部分
00000000: 48 65 6c 6c 6f Hello
应用场景
- 二进制调试:Wireshark、hexdump、xxd 的输出格式
- 颜色值:
#FF5733即 RGB 三通道的 Hex 表示 - MAC 地址:
00:1A:2B:3C:4D:5E - Magic Number:文件头标识(如 PNG 文件以
89504e47开头) - 哈希摘要:SHA-256 默认输出 64 字符 Hex 字符串
- 嵌入式开发:C 数组导出固件字节数据
- 加密密钥:AES-128 密钥以 32 字符 Hex 表示
优缺点
- ✅ 最直观,每个字节固定 2 字符,便于按字节定位
- ✅ 字符集最小(16 字符),任何场景都不会转义
- ✅ 大小写不敏感(解码时统一处理)
- ❌ 体积膨胀 100%,是三种编码中最大的
- ❌ 不适合大体积数据传输
Base32:人类友好的编码
RFC 4648 标准
RFC 4648 标准的 Base32 字符集为 A-Z(26 字母)+ 2-7(6 数字)共 32 字符。选择 2-7 而非 0-9 是为了避开 0(与 O 易混)和 1(与 I/L 易混)。
每 5 字节(40 位)数据拆分为 8 个 5 位段,每段映射到一个字符。不足 5 字节的尾部用 = 填充至 8 字符的倍数。
字节: H e l l o
二进制:01001000 01100101 01101100 01101100 01101111
5位段: 01001 00001 10010 10110 11000 11011 00011 01111
字符: J B S W Y 3 D P
「Hello」编码为 JBSWY3DP。
Crockford 变体
Douglas Crockford 设计的 Base32 变体专为人工输入场景优化:
- 字符集
0-9A-Z去除I/L/O/U(22 字母 + 10 数字 = 32) - 解码时自动归一化易混字符:
I/L→1,O→0 - 不使用
=填充 - 支持校验和:将原始字节序列视为大整数 mod 37,附加 1 个校验字符
应用场景
- TOTP 共享密钥:Google Authenticator 的 otpauth URI 中密钥用 Base32 编码
- 账号号码:银行账号、订单号,配合校验和识别输入错误
- 密钥指纹:SSH/PGP 公钥指纹,便于人工核对
- DNS 编码:DNS 协议不区分大小写,Base32 是天然适配
- 二维码短链:纯字母数字的二维码识别率更高
优缺点
- ✅ 不区分大小写,适合口述、手写
- ✅ 字符集仅字母数字,URL 友好,二维码友好
- ✅ Crockford 校验和可识别单字符输入错误
- ❌ 体积膨胀 60%,比 Base64 大
- ❌ RFC 4648 的
=填充在某些场景需额外处理
Base64:体积最小的编码
工作原理
Base64 字符集为 A-Za-z0-9+/ 共 64 字符,每 6 位映射到一个字符。每 3 字节(24 位)数据编码为 4 个字符。
字节: H e l
二进制:01001000 01100101 01101100
6位段: 010010 000110 010101 101100
字符: S G V s
「Hel」编码为 SGVs。
变体
- 标准 Base64:字符集含
+//,使用=填充 - URL 安全 Base64:
+→-,/→_,可选省略填充 - Base64URL:JWT、JWE 等场景的默认编码
应用场景
- 图片内联:Data URL
data:image/png;base64,... - JWT/JWE:三段式 JWT 与五段式 JWE 均用 Base64URL
- 邮件附件:MIME Base64 编码二进制附件
- CSS 资源:小图标内联减少 HTTP 请求
- API 传输:二进制数据通过 JSON 文本传输
优缺点
- ✅ 体积膨胀仅 33%,是三种编码中最小
- ✅ 通用性最强,几乎所有编程语言内置
- ❌ 含
+///=特殊字符,URL 不友好(需 URL 安全变体) - ❌ 大小写敏感,不适合口述
- ❌ 字符集含易混字符(
0/O、1/l/I)
三种编码的对比
膨胀率对比
| 原始字节数 | Hex 长度 | Base32 长度 | Base64 长度 |
|---|---|---|---|
| 1 | 2 | 8(含 6 填充) | 4(含 2 填充) |
| 3 | 6 | 8(含 1 填充) | 4 |
| 5 | 10 | 8 | 8(含 2 填充) |
| 24 | 48 | 40(含 2 填充) | 32 |
| 100 | 200 | 160 | 136(含 1 填充) |
可读性对比
| 维度 | Hex | Base32(Crockford) | Base64 |
|---|---|---|---|
| 大小写敏感 | 否 | 否 | 是 |
| 字符集大小 | 16 | 32 | 64 |
| 含特殊字符 | 否 | 否 | 是(+/=) |
| 易混字符处理 | 无 | I/L→1, O→0 | 无 |
| 校验和 | 无 | Crockford mod 37 | 无 |
| 二维码友好 | 中 | 高 | 中 |
| 口述友好 | 高(0-9A-F) | 高(去除易混) | 低(大小写 + 符号) |
编码后体积对比
原始数据(5 字节):Hello
Hex: 48656c6c6f (10 字符, 膨胀 100%)
Base32: JBSWY3DP (8 字符, 膨胀 60%)
Base64: SGVsbG8= (8 字符, 膨胀 60%, 含 1 填充)
注意:5 字节是 Base64 的「最差情况」(3 字节的倍数 + 2 字节尾部),实际大体积数据下 Base64 膨胀率稳定在 33%。
选型决策树
数据是否需要人工输入或口述?
├─ 是 → 数据是否需要校验和识别输入错误?
│ ├─ 是 → Crockford Base32(含校验和)
│ └─ 否 → 是否为 TOTP 共享密钥或 DNS 场景?
│ ├─ 是 → RFC 4648 Base32
│ └─ 否 → Crockford Base32(无校验和)
└─ 否 → 是否为 URL/二维码/OCR 场景?
├─ 是 → Base32(纯字母数字,二维码识别率高)
└─ 否 → 是否需要按字节定位或调试?
├─ 是 → Hex(每字节固定 2 字符)
└─ 否 → 体积是否敏感?
├─ 是 → Base64(膨胀最小 33%)
└─ 否 → Base64(通用性最强)
简化版选型口诀
- 要人工输入 → Base32(Crockford 变体 + 校验和)
- 要最小体积 → Base64(URL 安全变体用于 URL 场景)
- 要字节级调试 → Hex(xxd 风格 Hex dump)
- 要二维码识别率 → Base32(纯字母数字)
- 要 TOTP 密钥 → Base32(RFC 4648,RFC 6238 标准要求)
- 要 JWT/JWE → Base64URL(RFC 7515/7516 标准要求)
- 要颜色值/MAC 地址 → Hex(行业惯例)
JavaScript 实现要点
Hex 编码
// 最简实现:每字节转 2 字符
function encodeHex(text) {
const bytes = new TextEncoder().encode(text);
return Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
}
// "Hello" → "48656c6c6f"
Base32 编码(RFC 4648)
function encodeBase32(bytes, alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567') {
let output = '';
let buffer = 0; // 累积位
let bits = 0; // 当前累积位数
for (const byte of bytes) {
buffer = (buffer << 8) | byte;
bits += 8;
while (bits >= 5) {
bits -= 5;
output += alphabet[(buffer >> bits) & 0x1f];
}
}
// 处理剩余不足 5 位的尾部
if (bits > 0) {
output += alphabet[(buffer << (5 - bits)) & 0x1f];
}
// RFC 4648 填充 = 至 8 的倍数
while (output.length % 8 !== 0) output += '=';
return output;
}
Base64 编码
// 浏览器原生 btoa 仅支持 Latin1,需手动转 UTF-8 字节
function encodeBase64(text) {
const bytes = new TextEncoder().encode(text);
let binary = '';
for (const b of bytes) binary += String.fromCharCode(b);
return btoa(binary);
}
// "Hello" → "SGVsbG8="
关键陷阱
- UTF-8 编码:直接用
btoa(text)处理中文会抛InvalidCharacterError,必须先TextEncoder().encode() - Crockford 校验和精度:
value mod 37直接计算会因Number.MAX_SAFE_INTEGER丢失精度,需逐字节累积取模:mod = (mod * 256 + byte) % 37 - Hex dump 解析:xxd 风格输出含偏移量、双空格分隔符、ASCII 部分,不能简单移除所有非 hex 字符,需先正则识别格式再提取
- Base64 URL 安全:JWT/JWE 场景需将
+→-、/→_、=省略
真实应用场景对比
场景 1:存储用户密码重置令牌
令牌(Hex): a3f5b2c8d1e4f6a7b8c9d0e1f2a3b4c5
令牌(Base32): 7IY7YULGOJXV3LQBE5QVYLZ5XJQV3XQF
令牌(Base64URL): o_WyyNHk9qe4ydDh8qO0xQ
- 选 Hex:便于数据库存储与按字节调试
- 选 Base32:便于用户复制粘贴(不区分大小写)
- 选 Base64URL:体积最小,适合 URL 参数
场景 2:TOTP 共享密钥
密钥(原始字节): 48 65 6c 6c 6f
密钥(Base32): JBSWY3DP
密钥(Hex): 48656c6c6f
RFC 6238 TOTP 标准要求密钥以 Base32 编码,原因是:
- 不区分大小写,用户手动输入容错
- 字符集仅字母数字,二维码识别率高
- 无
+///=等需转义的字符
场景 3:嵌入式固件字节数组导出
// C 数组格式(Hex 变体)
const uint8_t firmware[] = {
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f,
0x72, 0x6c, 0x64, 0x21, 0x0a
};
这是 Hex 编码的 C 数组变体,嵌入式开发中固件烧录、Bootloader 升级、字库数据导出等场景的标准格式。
场景 4:哈希摘要展示
SHA-256("Hello")(Hex): 185f8db32271fe25f561a6fc938b2e26...
SHA-256("Hello")(Base64):GF+NuyMi3/4l9WGm/JK0FE1tsYU=
行业惯例是 Hex 展示,原因:
- 固定 64 字符,便于按字节比对
- 大小写不敏感,复制粘贴容错
- 不含特殊字符,任何终端都能显示
工具矩阵联动
本站的编码三工具形成「Base64 + Base32 + Hex」编码矩阵闭环:
- Base64 编解码工具:标准 + URL 安全变体
- Base32 编解码工具:RFC 4648 + Crockford 双变体 + 校验和
- Hex 十六进制编解码工具:5 种输出格式 + 多格式自动识别解码
- Base64 图片互转:图片与 Data URL 双向转换
- Hash 计算:SHA-1/256/512 摘要,输出 HEX 或 Base64
- JWT 解码:JWT 三段均为 Base64URL 编码
- JWE 解码:JWE 五段均为 Base64URL 编码
用户可:
- Hash 工具计算摘要后,用 Hex 工具切换为 C 数组格式导出
- Base64 工具解码 JWT 后,用 Base32 工具重新编码用于 DNS 场景
- Base64 图片工具生成 Data URL 后,用 Hex 工具查看图片字节流
- TOTP 密钥(Base32)用 Hex 工具转字节序列后调试 OTP 算法
总结
Base64、Base32、Hex 不是相互替代的关系,而是各自适配不同场景的编码工具:
- Base64 是「体积优先」的通用编码,适合机器间传输
- Base32 是「人类优先」的友好编码,适合人工输入与二维码场景
- Hex 是「调试优先」的直观编码,适合字节级查看与嵌入式开发
理解三种编码的字符集、膨胀率、可读性差异,才能在不同场景做出正确选型。掌握选型决策树的核心问题——「数据是否需要人工输入?」「是否需要按字节定位?」「体积是否敏感?」——就能快速定位到合适的编码方案。