背景:
在项目中,我们会上传文件或者图片到服务器,需要的时候再下载,这个时候我们可能会听到,把对方传来的 Base64 解码在上传到服务器;或者,直接把 Base64 码保存到数据库。所以就了解了一下这个 Base64
Base64 编码转换方式
本段引自阮一峰的网络日志
下面结合文字和具体例子,保证可以看得懂。
所谓 Base64,就是说选出 64 个字符:小写字母 a-z、大写字母 A-Z、数字 0-9、符号“+”、“/”(再加上作为垫字的“=”,实际上是65个字符)作为一个基本字符集。然后其他所有符号都转换成这个字符集中的字符。
具体来说转换方式可以分为以下四步:
- 将每三个字节作为一组,一共是 24 个二进制位
- 将这 24 个二进制分为 4 组,每组有 6 个二进制位
- 在每组前面加上两个 0 ,扩展成 32 个二进制位,即四个字节
- 根据下表,得到扩展后的每个字节的对应符号,这就是Base64的编码值
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
转码后的文本,会比未转码的大1/3左右,因为是将三个字节扩充到4个字节
具体例子:
演示英语单词Man如何转成Base64编码 :
第一步,"M"、"a"、"n"的ASCII值分别是77、97、110,对应的二进制值是01001101、01100001、01101110,将它们连成一个24位的二进制字符串010011010110000101101110。
第二步,将这个24位的二进制字符串分成4组,每组6个二进制位:010011、010110、000101、101110。
第三步,在每组前面加两个00,扩展成32个二进制位,即四个字节:00010011、00010110、00000101、00101110。它们的十进制值分别是19、22、5、46。
第四步,根据上表,得到每个值对应Base64编码,即T、W、F、u。
因此,Man 的 Base64 编码就是 TWFu 。
为什么用?
- 二进制文件转换为字符串,方便传输
- 简单加密
那么,假如是我们自己做的小项目,就是自己上传文件到服务器,那么就不需要 Base64,直接上传即可。此时Base64 意义不大。
在企业级项目中,前后端分离,很可能有很多个中心,而你的服务只是其中一个中心的一个微小服务,当别人需要使用你的服务的时候,难道别人直接把数据流传送给你?传一个字符串就能解决的事情,为什么要搞得那么复杂。
public class ForCheckAnyObject {
public static void main(String args[]) throws IOException {
String filePath = "D:" + File.separator + "2.txt";
File file = new File(filePath);
InputStream is = new FileInputStream(file);
//is.available():返回读取文件大小这多的字节
byte[] bytes = new byte[is.available()];
is.read(bytes);
is.close();
// sun.misc.BASE64Encoder
BASE64Encoder encoder = new BASE64Encoder();
String encodeString = encoder.encode(bytes);
System.out.println(encodeString);
// JDK8 新加入的 java.util.Base64
String encodeString1 = Base64.getEncoder().encodeToString(bytes);
System.out.println(encodeString1);
}
}
//经测试两个类生成的 Base64 码一样
//yKjP3rT6wusNCg==
分析上面的代码
- is.available():返回读取文件大小这么多的字节(再也不用想应该怎么样设置这个数组的大小了)
- sun.misc.BASE64Encoder 类对二进制数据进行加密
- java.util.Base64 类对二进制数据进行加密
具体分析
下面来分析两个不同类的具体用法
sun.misc.BASE64Encoder
这 sun 公司的一个类,虽然在我们开发中不需要引入第三方的库,但是 JDK8 中已经有替代方案,当然在 JDK8 以前就使用这个吧。
BASE64Encoder encoder = new BASE64Encoder();
String encodeString = encoder.encode(bytes);
BASE64Decoder decoder=new BASE64Decoder();
byte[] bytes1=decoder.decodeBuffer(encodeString);
上面就是正常 new 初始化,再进行加/解密
java.util.Base64
这是 JDK8 开始才引入的类
//加密
String encodeString1 = Base64.getEncoder().encode(bytes).toString();
//解密
bytes2=Base64.getDecoder().decode(encodeString1);
下面是 JDK8 中 java.util.Base64 类的源码
//因为是私有构造函数,所以不能使用 new 实例化
private Base64() {}
//提供静态方法,实例化 Encoder 对象
public static Encoder getEncoder() {
return Encoder.RFC4648;
}
// java.util.Base64 类中的静态内部类
public static class Encoder {
///
public byte[] encode(byte[] src) {
////
}
public byte[] decode(String src) {
///
}
///
}
//也是返回一个 Encoder 对象,只不过加密的 64 个字符;
// 将符号“+”、“/” 换成了 '-', '_',其余操作不便
Base64.getUrlEncoder().encode(bytes);
// 主要是URL中反斜杠 /有特殊的含义,直接编码会不太安全,所以URL编码会使用下划线 _ 来替代 /。
总结
核心作用应该是传输数据的正确性,有些网关或系统只能使用 ASCII 字符。Base64 就是用来将非 ASCII 字符的数据转换成 ASCII 字符的一种方法,而且 base64 特别适合在 http,mime 协议下快速传输数据。
加密的作用很小,我们可以直接用 JDK 提供的方法就解密了,所以最主要的还是数据传输的正确性,和方便
这个是作用在二进制数据上面的。即先把一个文件转为二进制,在对其进行加密,最终我们得到的字符串其实就是文件的内容。