技术分享
Base64编码大全解
00 分钟
2025-2-28
2025-2-28
type
status
date
slug
summary
tags
category
icon
password
/
URL 编码是对字符进行编码,表示成 %xx 的形式,而 Base64 编码是对二进制数据进行编码,表示成文本格式。
 

为什么需要 Base64 编码

Base64 编码的目的是把二进制数据变成文本格式,这样在很多文本中就可以处理二进制数据。例如,电子邮件协议就是文本协议,如果要在电子邮件中添加一个二进制文件(比如图片),就可以用 Base64 编码,然后以文本的形式传送。
而且有时候一些路由器等硬件也不兼容二进制,或者一些网络协议不兼容,因此得转为字符形式。
还有的时候,使用文本形式能减少一次 http 请求,提高效率:打开 google 的首页,就能看到某些样式中的图片不是一个资源地址,而是 base64 编码的字符串。通过 base64 来传输图片,然后浏览器解码该 base64,就能得到图片了。
注意:并不是什么图片都适合用 base64 来处理,因为图片越大,转换的 base64 的字符串就越长,对带宽的要求更高了。
​​
notion image

Base64 编码转换规则

Base64 编码可以把任意长度的二进制数据变为纯文本,且只包含 A​ ~Z​,a​ ~z​,0​ ~9​、+​、/​、= ​这些字符。它的原理是把 3 字节的二进制数据按 6bit 一组,用 4 个 int 整数表示,然后把这个整数作为索引查表,得到对应的字符,最终得到编码后的字符串。
  • 6 位整数的范围总是 0​ ~63​,所以,能用 64 个字符表示:
  • 字符 A​ ~Z​对应索引 0​ ~25​,
  • 字符 a​ ~z​对应索引 26​ ~51​,
  • 字符 0​ ~9​对应索引 52​ ~61​,
  • 最后两个索引 62​、63​分别用字符 +​和 /​表示。
索引表如下(摘自 RFC2045):
Table 1: The Base64 Alphabet
索引
对应字符
索引
对应字符
索引
对应字符
索引
对应字符
0
A
17
R
34
i
51
z
1
B
18
S
35
j
52
0
2
C
19
T
36
k
53
1
3
D
20
U
37
l
54
2
4
E
21
V
38
m
55
3
5
F
22
W
39
n
56
4
6
G
23
X
40
o
57
5
7
H
24
Y
41
p
58
6
8
I
25
Z
42
q
59
7
9
J
26
a
43
r
60
8
10
K
27
b
44
s
61
9
11
L
28
c
45
t
62
+
12
M
29
d
46
u
63
/
13
N
30
e
47
v
14
O
31
f
48
w
15
P
32
g
49
x
16
Q
33
h
50
y
举个例子:3 个 byte 数据分别是 e4、b8、ad,按 6bit 分组得到 39、0b、22 和 2d(十六进制下):
┌───────────────┬───────────────┬───────────────┐ │ e4 │ b8 │ ad │ └───────────────┴───────────────┴───────────────┘ ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐ │1│1│1│0│0│1│0│0│1│0│1│1│1│0│0│0│1│0│1│0│1│1│0│1│ └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ ┌───────────┬───────────┬───────────┬───────────┐ │ 39 │ 0b │ 22 │ 2d │ └───────────┴───────────┴───────────┴───────────┘
根据查表可得最后的字符是 5Lit​ 这四个字符。
需要注意的是,根据 ASCII 编码,4 个字符占了 4*8=32 个 bit,比起原始的 bit 位数多了 1/3,传输效率会降低。字符越少,编码的效率就会越低。
如果把 Base64 的 64 个字符编码表换成 32 个、48 个或者 58 个,就可以使用 Base32 编码,Base48 编码和 Base58 编码。

Java 中的 Base64 编码

Java 提供了不少类来对二进制数据进行 Base64 编码和解码。
例如对上述例子进行编码:
import java.util.Base64; public class TestBase64{ public static void main(String[] args) { byte[] input = new byte[]{ (byte)0xe4, (byte)0xb8, (byte)0xad}; String base64Encoded = Base64.getEncoder().encodeToString(input); System.out.println(base64Encoded); //5Lit } }
解码:以补码形式输出结果
byte[] output = Base64.getDecoder().decode("5Lit"); System.out.println(Arrays.toString(output)); //[-28, -72, -83]

如果不是 3 的倍数...

如果输入的 byte[] ​数组长度不是 3 的整数倍肿么办?这种情况下,需要对输入的末尾补一个或两个 0x00​,编码后,在结尾加一个 = ​表示补充了 1 个 0x00​,加两个 = ​表示补充了 2 个 0x00​,解码的时候,去掉末尾补充的一个或两个 0x00 ​即可。
实际上,因为编码后的长度加上 = ​总是 4 的倍数,所以即使不加 = ​也可以计算出原始输入的 byte[]​。Base64 编码的时候可以用 withoutPadding() ​去掉 =​,解码出来的结果是一样的:
import java.util.Arrays; import java.util.Base64; public class TestBase642 { public static void main(String[] args) { byte[] input = new byte[] { (byte) 0xe4, (byte) 0xb8, (byte) 0xad, 0x21 }; String b64encoded = Base64.getEncoder().encodeToString(input); String b64encoded2 = Base64.getEncoder().withoutPadding().encodeToString(input); System.out.println(b64encoded); System.out.println(b64encoded2); byte[] output = Base64.getDecoder().decode(b64encoded2); System.out.println(Arrays.toString(output)); } }
运行结果:
5LitIQ== 5LitIQ [-28, -72, -83, 33]
因为标准的 Base64 编码会出现 +​、/ ​和 =​,所以不适合把 Base64 编码后的字符串放到 URL 中。一种针对 URL 的 Base64 编码可以在 URL 中使用的 Base64 编码,它仅仅是把 + ​变成 -​,/ ​变成 _​:
import java.util.Arrays; import java.util.Base64; public class TestBase643 { public static void main(String[] args) { byte[] input = new byte[] { 0x01, 0x02, 0x7f, 0x00 }; String b64encoded = Base64.getUrlEncoder().encodeToString(input); System.out.println(b64encoded); byte[] output = Base64.getUrlDecoder().decode(b64encoded); System.out.println(Arrays.toString(output)); } }
运行结果:
AQJ_AA== [1, 2, 127, 0]
上一篇
nf天选35种职业
下一篇
软件下载

评论
Loading...