Base64
Base64 编解码笔记
Base64 是一种用 64 个字符来表示任意二进制数据的方法。
RFC4648 介绍了 Base64/32/16 编码规范
https://datatracker.ietf.org/doc/html/rfc4648
为什么要使用Base64?
Base64 编码的作用:由于某些系统中只能使用 ASCII 字符。Base64 就是用来将非 ASCII 字符的数据转换成 ASCII 字符的一种方法。
Base64 是一种很常见的编码规范,其作用是将二进制序列转换为人类可读的 ASCII 字符序列,常用在需用通过文本协议(比如HTTP和SMTP)来传输二进制数据的情况下。Base64 并不是加密解密算法,尽管我们有时也听到使用Base64来加密解密的说法,但这里所说的加密与解密实际是指编码(encode)和解码(decode)的过程,其变换是非常简单的,仅仅能够避免信息被直接识别。
byte[] 类型字段可接收 base64 字符串
SpringBoot 对外暴露 byte[] 类型的字段可以接收 base64 字符串,自动转换为字节数组
public class FeatureExtractRequest {
@NotEmpty(message = "image cannot be empty!")
private byte[] image;
}
可以直接在 postman 中如下传参:
{
"image": "/9j/...."
}
但要注意:
- base64 字符串长度是 4 的倍数,否则转换会报错
- 之前好像遇到过 url 编码的 base64 也会报错,spring 默认只支持 basic 编码的 base64 自动转换为 byte[]
Base64使用场景
它的使用场景有很多,比如:
1、将图片等资源文件以Base64编码形式直接放于代码中,使用的时候反Base64后转换成Image对象使用;
2、有些文本协议不支持不可见字符的传递,只能转换成可见字符来传递信息。
3、有时在一些特殊的场合,大多数消息是纯文本的,偶尔需要用这条纯文本通道传一张图片之类的情况发生的时候,就会用到Base64,比如多功能Internet 邮件扩充服务(MIME)就是用Base64对邮件的附件进行编码的。
4、base64 最早就是用来邮件传输协议中的,原因是邮件传输协议只支持 ascii 字符传递,因此如果要传输二进制文件,如:图片、视频是无法实现的。因此 base64 就可以用来将二进制文件内容编码为只包含 ascii 字符的内容,这样就可以传输了
Base64编码过程
Base64 使用 64 个通用的可打印字符来存储和表示二进制字数据,同时也可以进行简单的加密(Base64 编码是可逆的,不是真正的加密),生成不可读文本。
1、准备一个包含 64 个字符的数组作为码表,包含 大小写、数字、加号、斜线['A', 'B', 'C', ... 'a', 'b', 'c', ... '0', '1', ... '+', '/']
2、二进制数据是以字节为单位的。对二进制数据进行处理,每 3 个字节一组,一共是 3x8=24bit, 划为 4 组,每组正好 6 个 bit, 这样我们得到 4 个 [0,63] 范围内的数字作为索引,然后查表,获得相应的 4 个字符,就是编码后的字符串。
3、如果要编码的二进制数据的字节数不是 3 的倍数,最后会剩下 1 个或 2 个字节,在原始二进制码末尾补 0 直到恰好是 6bits 的倍数,然后查表转换为字符编码,再在最后补 1 到 2 个 =
号,使总的字符个数是 4 的整数倍。
所以,Base64 编码会把 3 字节的二进制数据编码为 4 字节的文本数据,长度增加 33%, 好处是编码后的文本数据可以在邮件正文、网页等直接显示。
例如
1、一字节的二进制数据
0000 0001
1 个字节是 8bits, 后补 4 个 0 得到 12bit,成为 6bit 的整数倍,得到
0000 0001 0000
6bit 一组,共两组 000000 和 010000, 分别是 0 和 16, 查表得
AQ
后补 2 个 =
得 AQ==
3、两字节的二进制数据
0000 0000 0000 0000
2 个字节是 16bit, 后补 2 个 0 得到 18bit,成为 6bit 的整数倍,得到
0000 0000 0000 0000 00
6bit 一组,共三组 000000 000000 000000 分别是 0, 0, 0, 查表得
AAA
后补 1 个 =
得 AAA=
可以发现,每一个 =
代表二进制源码末尾添加了 2bits 的 0, Base64 编码后字串的长度将是 4 的整数倍,根据末尾 =
的个数计算编码过程中补 0 的个数,就可以正常解码。
URL safe的Base64编码
由于标准的 Base64 编码后可能出现字符 +
和 /
, 在 URL 中就不能直接作为参数,所以又有一种 “url safe” 的 base64 编码,其实就是把字符 + 和 / 分别变成 - 和 _
Java原生的Base64编解码工具类
Java 8 在 java.util
包中新增了 Base64
编解码类,直接就可以用。
java.util.Base64
包括下面三种 Base64 编解码器
1 Basic编码
2 URL编码
3 MIME编码
Basic 编解码
Basic 编码是标准的 BASE64 编码,用于处理常规的需求:输出的内容不添加换行符,而且输出的内容由字母加数字组成。
URL 编解码
由于 URL 对斜线 /
有特殊的意义,因此 URL 编码需要替换掉它,使用下划线 _
替换。
URL 编解码器和 Basic 的不同就在于会将编码后的结果中的 /
替换为 _
MIME 编解码
MIME 编解码器和 Basic 的不同在于会自动换行,每行不超过 76 个字符,自动用 \r\n
分割以实现换行。但是结果中还是会有 /
@Test
public void testBase64Codec() {
System.out.println("Basic 编解码");
String basic = Base64.getEncoder().encodeToString("subjects?abcd".getBytes(StandardCharsets.UTF_8));
System.out.println(basic);
System.out.println(new String(Base64.getDecoder().decode(basic), StandardCharsets.UTF_8));
System.out.println("\nURL 编解码");
String url = Base64.getUrlEncoder().encodeToString("subjects?abcd".getBytes(StandardCharsets.UTF_8));
System.out.println(url);
System.out.println(new String(Base64.getUrlDecoder().decode(url), StandardCharsets.UTF_8));
System.out.println("\nMIME 编解码");
String mime = Base64.getMimeEncoder().encodeToString(("subjects?abcdsubjects?abcdsubjects?abcdsubjects?abc" +
"dsubjects?abcdsubjects?abcdsubjects?abcd").getBytes(StandardCharsets.UTF_8));
System.out.println(mime);
System.out.println(new String(Base64.getMimeDecoder().decode(mime), StandardCharsets.UTF_8));
}
结果
Basic 编解码
c3ViamVjdHM/YWJjZA==
subjects?abcd
URL 编解码
c3ViamVjdHM_YWJjZA==
subjects?abcd
MIME 编解码
c3ViamVjdHM/YWJjZHN1YmplY3RzP2FiY2RzdWJqZWN0cz9hYmNkc3ViamVjdHM/YWJjZHN1Ympl
Y3RzP2FiY2RzdWJqZWN0cz9hYmNkc3ViamVjdHM/YWJjZA==
subjects?abcdsubjects?abcdsubjects?abcdsubjects?abcdsubjects?abcdsubjects?abcdsubjects?abcd
封装输入输出流
编码器封装输出流,将给定字符串编码为 Base64 后写入文件输出流
解码器封装输入流,对 Base64 编码的文件流进行解码
@Test
public void wrapStreamTest() throws Exception {
// 创建的文件是 target/test-classes/file-base64.txt
File file = new File(this.getClass().getResource("/").getPath() + "file-base64.txt");
try (
// 编码器封装输出流,将给定字符串编码为 Base64 后写入文件输出流
OutputStream os = Base64.getEncoder().wrap(new FileOutputStream(file));
) {
IOUtils.write(System.getProperties().toString(), os, StandardCharsets.UTF_8);
}
try (
// 解码器封装输入流,对 Base64 编码的文件流进行解码
InputStream is = Base64.getDecoder().wrap(new FileInputStream(file))
) {
IOUtils.readLines(is, StandardCharsets.UTF_8).forEach(System.out::println);
}
}
Java 8实现BASE64编解码
http://masikkk.com/article/Java-Basic/#base64-%E7%BC%96%E7%A0%81
Linux base64命令
对文件、标准输入进行 base64 编解码,并打印到标注输出
-d, –decode 解码数据
-i, –ignore-garbag 解码时忽略非字母字符
-w, –wrap=字符数 在指定的字符数后自动换行(默认为76),0 为禁用自动换行
–version 显示版本信息并退出
如果没有指定文件,或者文件为”-“,则从标准输入读取。
数据以 RFC 3548 规定的 Base64 字母格式进行编码。 解码时,输入数据(加密流)可能包含一些非有效 Base64 字符的新行字符。可以尝试用 –ignore-garbage 选项来恢复加密流中任何非 base64 字符。
base64
从标准输入中读取数据,按Ctrl+D结束输入。将输入的内容编码为base64字符串输出。
echo "str" | base64
将字符串 str+换行 编码为base64字符串输出。echo -n "str" | base64
将字符串str编码为base64字符串输出,最后没有换行。注意与上面的差别。
base64 file
从指定的文件file中读取数据,编码为base64字符串输出。
base64 -d
从标准输入中读取已经进行base64编码的内容,解码输出。
base64 -d -i
从标准输入中读取已经进行base64编码的内容,解码输出。加上-i参数,忽略非字母表字符,比如换行符。
echo "str" | base64 -d
将base64编码的字符串str+换行 解码输出。echo -n "str" | base64 -d
将base64编码的字符串str解码输出,最后没有换行。注意与上面的差别。
base64 -d file
从指定的文件file中读取base64编码的内容,解码输出。
Spring提供的Base64Utils工具类
public static String encodeToString(byte[] src)
字节数组编码为 base64
commons-codec提供的Base64工具类
public static String encodeBase64String(final byte[] binaryData)
Hex十六进制转babse64
在线hex转base64
方法一 在线工具
打开这个在线工具 https://the-x.cn/zh-cn/base64
“常规base64”,填入 十六进制 值(注意开头的0x要去掉),“编码源格式” 选择 Hex 转 base64,点击“编码”,得到 base64 编码的十六进制。
java hex转base64
方法二 java 代码
写个 java 代码单测,使用 commons-lang-codec 的 Hex
工具类把十六进制字符串转为 byte 数组,再用 spring-core 的 Base64Utils 转换为 base64
@Test
public void hexoToByteArray() throws Exception {
byte[] bytes = Hex.decodeHex("4E6AE63D".toCharArray());
System.out.println("base64:");
System.out.println(Base64Utils.encodeToString(bytes));
}
上一篇 护肤
下一篇 JaCoCo
页面信息
location:
protocol
: host
: hostname
: origin
: pathname
: href
: document:
referrer
: navigator:
platform
: userAgent
: