第 2 课
Base64 编码原理
比特分组、六位一组与 64 字符字母表。
Base64 的核心思想很常见:比特串、2 的幂、再加上一张 索引表(字母表)。没有词典、不做压缩——只是把比特按固定规则重排后用可打印字符表示。
从字节到位流
一个字节八个比特;三个字节共有 24 个比特,按先后顺序拼接成一个连续位串:
字节1:########
字节2:########
字节3:######## → 顺序连接成 24 bit
Base64把这 24 个比特划分为 四个“六位组”(sextets):
[######][######][######][######]
↑ ↑ ↑ ↑
第1组 第2组 第3组 第4组
每个六位数的取值范围是 0–63,用来索引 64 个符号。这就是名称里 base 64 的含义:像在写 64 进制,只是把“数字符号”换成了可打印 ASCII。
常见标准字母表(RFC 一脉)
最常见映射为:
0–25 → A–Z
26–51 → a–z
52–61 → 0–9
62 → '+'
63 → '/'
解码则逆过来:符号 → 六个比特 → 再拼回原始的八位字节。
徒手走一遍两个小例子(感受一下填充为何会冒头)
日常工作不必手写,但能强化直觉。取 ASCII "Hi":
H=0x48(01001000)i=0x69(01101001)
拼接得到 16 个比特:0100100001101001。
为了在逻辑上对齐到六位一组,编码器会在 右侧 用 0 补齐,直到长度为 6 的倍数——具体如何表现为输出里的字符与 =,下一课展开:
010010 | 000110 | 100100 |
18 6 36
若输入在此时结束,第 4 个六位组需要借助 填充规则补齐;解码器会根据 = 知道哪些六位组是“补出来的”。库会替你处理这些——理解分组后你就能明白 为什么编码后更长,以及为什么在传输错误时解码结果会像“整块错位”。
为什么编码后体积大约多出三分之一
三组字节(24 比特)会变成 四个编码字符——同样的信息量被摊开成可打印形态。粗略来说:若输入有 n 个字节,编码后大约 ceil(4n/3) 个字符(不计填充);若 n % 3 ≠ 0,末尾还会出现 =。体积换 兼容性,这是刻意的取舍。
解码的对称性
解码步骤:
- 按同一种字母表,把字符映射回 0–63(若混用 URL-safe 变体,须与编码端一致)。
- 将所有六位值拼成一个连续比特串。
- 从左到右按 8 比特切回字节。
若字符串里有非法符号、混入不可见空白、或选了错误的字母表,= 个数不对——解析就会失败;部分宽松实现在边界处还可能产生 不一致的行为,这是为什么生产代码应坚持严格校验。
要点小结
Base64 把输入比特 按六位重切分,并为每组选取 64 个约定字符中的一个。头脑中有了“六位一组”这张图,后续的 填充 与 URL-safe 替换就只是在这个模型上的两个小补丁。