Skip to main content

9. Illustrations and Examples (图示和示例)

为了在二进制和base编码之间进行转换,输入被存储在一个结构中,输出被提取出来。


Base64编码图示

以下是Base64的情况,该图借自 [5]:

输入: 3个八位字节
+--第1个八位字节-+-第2个八位字节-+--第3个八位字节-+
|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
+-----------+---+-------+-------+---+-----------+
|5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|
+--1.索引--+--2.索引--+--3.索引--+--4.索引--+

输出: 4个字符

详细说明

输入的24位被重新分组为4个6位组:

位索引: 23 22 21 20 19 18 | 17 16 15 14 13 12 | 11 10 9 8 7 6 | 5 4 3 2 1 0
|----字符1----| |----字符2----| |---字符3---| |---字符4---|

Base32编码图示

以下是Base32的情况,该图借自 [7]。Base32值中的每个连续字符表示底层八位字节序列的5个连续位。因此,每组8个字符表示5个八位字节的序列(40位)。

输入: 5个八位字节 (40位)
1 2 3
01234567 89012345 67890123 45678901 23456789
+--------+--------+--------+--------+--------+
|< 1 >< 2| >< 3 ><|.4 >< 5.|>< 6 ><.|7 >< 8 >|
+--------+--------+--------+--------+--------+
<===> 第8个字符
<====> 第7个字符
<===> 第6个字符
<====> 第5个字符
<====> 第4个字符
<===> 第3个字符
<====> 第2个字符
<===> 第1个字符

详细说明

输入的40位被重新分组为8个5位组:

位索引: 39-35 | 34-30 | 29-25 | 24-20 | 19-15 | 14-10 | 9-5 | 4-0
字符1 字符2 字符3 字符4 字符5 字符6 字符7 字符8

Base64编码示例(带详细步骤)

以下Base64数据示例来自 [5],已更正。

示例1: 完整的3字节组

输入数据: 0x14fb9c03d97e
十六进制: 1 4 f b 9 c | 0 3 d 9 7 e
8位: 00010100 11111011 10011100 | 00000011 11011001 01111110
6位: 000101 001111 101110 011100 | 000000 111101 100101 111110
十进制: 5 15 46 28 0 61 37 62
输出: F P u c A 9 l +

示例2: 2字节输入(需要1个填充)

输入数据: 0x14fb9c03d9
十六进制: 1 4 f b 9 c | 0 3 d 9
8位: 00010100 11111011 10011100 | 00000011 11011001
用00填充 ↓
6位: 000101 001111 101110 011100 | 000000 111101 100100
十进制: 5 15 46 28 0 61 36
用=填充 ↓
输出: F P u c A 9 k =

示例3: 1字节输入(需要2个填充)

输入数据: 0x14fb9c03
十六进制: 1 4 f b 9 c | 0 3
8位: 00010100 11111011 10011100 | 00000011
用0000填充 ↓
6位: 000101 001111 101110 011100 | 000000 110000
十进制: 5 15 46 28 0 48
用=填充 ↓ ↓
输出: F P u c A w = =

编码过程可视化

Base64编码过程

步骤1: 输入分组
输入: [Byte1] [Byte2] [Byte3]
8位 8位 8位

24位总计

步骤2: 重新分组
[6位] [6位] [6位] [6位]
↓ ↓ ↓ ↓
索引1 索引2 索引3 索引4

步骤3: 查表转换
索引 → 字符
↓ ↓
输出: [Char1][Char2][Char3][Char4]

Base32编码过程

步骤1: 输入分组
输入: [Byte1][Byte2][Byte3][Byte4][Byte5]
8位 8位 8位 8位 8位

40位总计

步骤2: 重新分组
[5位][5位][5位][5位][5位][5位][5位][5位]
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
索引1 索引2 索引3 索引4 索引5 索引6 索引7 索引8

步骤3: 查表转换
索引 → 字符
↓ ↓
输出: [C1][C2][C3][C4][C5][C6][C7][C8]

填充示例对比

Base64填充

输入字节数输出字符填充说明
3XXXX完整组
2XXX=1个=缺1字节
1XX==2个=缺2字节

Base32填充

输入字节数输出字符填充说明
5XXXXXXXX完整组
4XXXXXXX=1个=缺1字节
3XXXXX===3个=缺2字节
2XXXX====4个=缺3字节
1XX======6个=缺4字节

实际转换示例

文本编码

输入: "Hello"
ASCII码: H=72, e=101, l=108, l=108, o=111
十六进制: 0x48 0x65 0x6C 0x6C 0x6F

Base64:
01001000 01100101 01101100 → SGVs
01101100 01101111 [补零] → bG8=
输出: "SGVsbG8="

Base32:
01001000 01100101 01101100 01101100 01101111
→ "JBSWY3DP"

Base16:
→ "48656C6C6F"

二进制数据编码

输入: [0xFF, 0x00, 0xAA]
二进制: 11111111 00000000 10101010

Base64:
111111 110000 000010 101010
63 48 2 42
/ w C q
输出: "/wCq"

Base32:
11111 11100 00000 01010 10100
31 28 0 10 20
7 4 A K U
输出: "74AKU==="

Base16:
输出: "FF00AA"

边界情况示例

空输入

输入: "" (0字节)
Base64: ""
Base32: ""
Base16: ""

所有编码都返回空字符串

单字节

输入: [0x00]

Base64: "AA=="
Base32: "AA======"
Base16: "00"

全0字节

输入: [0x00, 0x00, 0x00]

Base64: "AAAA"
Base32: "AAAAAAAA"
Base16: "000000"

全1字节

输入: [0xFF, 0xFF, 0xFF]

Base64: "////"
Base32: "77777777"
Base16: "FFFFFF"

编码效率对比

原始数据: 100字节

Base64:
输出: 136字节
效率: 100/136 ≈ 73.5%
膨胀: +36%

Base32:
输出: 160字节
效率: 100/160 = 62.5%
膨胀: +60%

Base16:
输出: 200字节
效率: 100/200 = 50%
膨胀: +100%

实用技巧

快速估算输出长度

Base64:
输出字符数 ≈ (输入字节数 × 4 / 3) 向上取整到4的倍数

Base32:
输出字符数 ≈ (输入字节数 × 8 / 5) 向上取整到8的倍数

Base16:
输出字符数 = 输入字节数 × 2

填充检测

Base64:
无填充: 字符数是4的倍数
1个=: 原始数据模3余2
2个=: 原始数据模3余1

Base32:
无填充: 字符数是8的倍数
根据填充数量可推导原始长度

调试技巧

手工验证

1. 选择简单输入
示例: "A" (0x41)

2. 转换为二进制
0x41 = 01000001

3. 按位分组
Base64: 010000 01[0000]
Base32: 01000 001[00]

4. 查表验证
Base64: Q Q (+ 填充)
Base32: I E (+ 填充)

常见错误诊断

错误输出特征:
❌ 长度不正确 → 检查填充逻辑
❌ 乱码字符 → 检查字母表
❌ 解码失败 → 验证输入有效性

这些示例和图示帮助理解Base编码的内部工作原理,对于实现和调试都非常有用。