Base64 编码原理:数据到可打印字符的转换

FreeGuideOnline 最新 2026-06-18

Base64 编码原理:数据到可打印字符的转换

Base64 是最常见的一种将二进制数据转换为文本字符串的编码方式,常用于在只能处理文本的渠道(如电子邮件、JSON、XML)中传输图片、文件等数据。它的核心思想是把任意 8 位字节序列,转化为仅由 64 个可打印字符组成的字符串,并且保证转换后的长度比原始数据增加约 33%。

为什么需要 Base64?

许多传输协议和存储格式都是为文本设计的。如果直接将图片、音频等二进制数据嵌入,可能会因为其中包含不可见字符(如终止符、换行符)或与控制字符冲突,导致数据损坏。Base64 将二进制数据映射到一个安全的字符集范围,有效避免了这类问题。你可以在 HTML 中用 <img src="data:image/png;base64,..." /> 直接嵌入图片,也可以在电子邮件 MIME 附体中看到其身影。

核心原理:分块与映射

Base64 编码的过程可以拆解为三个步骤:

  1. 将原始数据视为连续的比特流,按照每 6 比特为一组进行划分。
  2. 把每个 6 比特组当成一个索引值(范围 0~63),去查一张固定的 64 字符映射表。
  3. 用查到的字符替换每一组,并在末尾补充等号 = 作为填充(如果需要的话)。

而解码则是完全相反的过程:去掉等号,把每个字符还原成 6 比特索引,再拼接成原始字节。

映射表(Base64 字母表)

Base64 标准(RFC 4648)定义了如下映射:

索引(二进制) 字符 索引(二进制) 字符 索引(二进制) 字符 索引(二进制) 字符
0 (000000) A 16 (010000) Q 32 (100000) g 48 (110000) w
1 (000001) B 17 (010001) R 33 (100001) h 49 (110001) x
2 (000010) C 18 (010010) S 34 (100010) i 50 (110010) y
3 (000011) D 19 (010011) T 35 (100011) j 51 (110011) z
4 (000100) E 20 (010100) U 36 (100100) k 52 (110100) 0
5 (000101) F 21 (010101) V 37 (100101) l 53 (110101) 1
6 (000110) G 22 (010110) W 38 (100110) m 54 (110110) 2
7 (000111) H 23 (010111) X 39 (100111) n 55 (110111) 3
8 (001000) I 24 (011000) Y 40 (101000) o 56 (111000) 4
9 (001001) J 25 (011001) Z 41 (101001) p 57 (111001) 5
10 (001010) K 26 (011010) a 42 (101010) q 58 (111010) 6
11 (001011) L 27 (011011) b 43 (101011) r 59 (111011) 7
12 (001100) M 28 (011100) c 44 (101100) s 60 (111100) 8
13 (001101) N 29 (011101) d 45 (101101) t 61 (111101) 9
14 (001110) O 30 (011110) e 46 (101110) u 62 (111110) +
15 (001111) P 31 (011111) f 47 (101111) v 63 (111111) /

这个表包含 26 个大写字母、26 个小写字母、10 个数字以及 +/,共 64 个字符。在某些 URL 安全的变体中,+/ 会被替换为 -_

编码过程详解:从字节到字符

我们以字符串 Man 为例逐步演示。

第一步:获取原始字节

M, a, n 三个字符的 ASCII 码分别是 7797110。写成 8 位二进制:

  • M → 01001101
  • a → 01100001
  • n → 01101110

将它们拼接成一个 24 位的比特流:

01001101 01100001 01101110

第二步:重新划分为 6 位一组

从高位到低位,每 6 位切一刀:

010011 | 010110 | 000101 | 101110

不足的部分会自动在末尾补零,但我们先处理完整的 24 位。

将每组转换为十进制索引:

  • 010011 → 19
  • 010110 → 22
  • 000101 → 5
  • 101110 → 46

第三步:查表得到 Base64 字符

  • 19 → T
  • 22 → W
  • 5 → F
  • 46 → u

因此 Man 的 Base64 编码结果是 TWFu。解码时,将这四个字符还原为 19、22、5、46,拼成 24 位二进制,再按 8 位切分即得到原始三个字节。

遇到不足 3 字节的数据怎么办?——填充(Padding)

Base64 每次处理 3 个字节(24 位)输出 4 个字符。当原始数据长度不是 3 的倍数时,就会出现末尾分组不满 6 位的情况。处理规则如下:

  • 剩余 1 个字节(8 位):先取出高 6 位映射为一个字符,剩下的 2 位低位后面补 4 个零,形成第二个 6 位组,映射为第二个字符。然后补两个 = 使最终长度为 4 的倍数。
  • 剩余 2 个字节(16 位):将它们切分为前 6 位、中间 6 位、最后 4 位。将前两个 6 位映射为字符,最后一个 4 位后面补两个零凑成 6 位映射为第三个字符。最后补一个 =

举例:单词 Ma 只有两个字节。

  • M → 01001101
  • a → 01100001 拼接:01001101 01100001

按 6 位分组:

010011 | 010110 | 0001?? 

前两组完整,第三组只有 4 位(0001),需要补两个零成为 000100。

索引:19(T)、22(W)、4(E,因为 000100 = 4)。由于原数据只有 2 字节,输出应有 4 个字符,所以补一个 =,得到 TWE=

解码时,= 表示填充,遇 = 停止处理后面的填充位。

解码过程简述

解码就是编码的逆过程:

  1. 去掉字符串末尾的所有 =
  2. 将每个 Base64 字符映射回 6 位索引值。
  3. 将所有索引值拼接为一个长比特流。
  4. 按 8 位一组划分,忽略尾部不足 8 位的零填充(因为这些填充位是由添加的 = 标记的,实际上多余比特一定是 0)。
  5. 将每个 8 位二进制转换回字节,得到原始数据。

例如 TWE=:去掉 =,剩余 TWE。查表:19、22、4。二进制:010011 010110 000100。拼接:010011010110000100。按 8 位分组:01001101(77)01100001(97)。第三组 00010000 中第四个字节只有 4 位有效,由于原始数据只有 2 字节,所以丢弃,恢复出 Ma

编码后的数据膨胀

Base64 编码会导致数据大小增加约 33%(准确说是输入每 3 字节变成 4 字节,增幅为 4/3 - 1 = 1/3 ≈ 33.3%)。对于大文件,要权衡传输便利性和体积增长。此外,有些实现会在编码字符串中插入换行(每 76 个字符一行),以供邮件等限制行长的协议使用。

常见应用场景

  • 数据 URI:在 HTML 或 CSS 中内联小图片、字体。
  • 电子邮件附件:MIME 标准使用 Base64 编码二进制附件。
  • 简单加密:Base64 本身不是加密,但常被用来混淆或编码凭证(如 HTTP Basic 认证中的 用户名:密码 Base64 编码)。
  • 存储二进制到 JSON:JSON 不支持原始二进制,可先将二进制编码为 Base64 字符串再存放。

理解 Base64 的原理,不仅能帮助你正确使用它,还能在调试接口、处理编码问题时快速发现问题。只要记住:6 位一组,查表映射,3 字节变 4 字符,不够就补等号,整个算法就清晰了。