概述
首先,我們先來說下什么是Base64編碼,然后再來學習下Java中Base64編碼的使用。
歷史
??Base64算法最早是為了解決電子郵件傳輸的問題的,早先的郵件傳輸協議中只支持ASCII碼傳遞,如果要傳輸二進制文件,如圖片和視頻,是無法傳輸的,而BASE64可以將二進制文件內容編碼成為只包含ASCII碼的內容,這樣就可以傳輸了。
??Base64算法大家常常說成是加密算法,但準確的來說,Base64不是一種加密算法,只能算是一種基于64個字符的編碼算法。
??它有一個字符映射表,每個字符映射了一個十進制編碼,共映射了64個字符。Base64將給定的數據經二進制轉換后與字符映射表相對應,得到所謂的密文;映射表如下,映射表的最后是一個等號,是作為補位符用來補位的。
編號 | 字符 | 編號 | 字符 | 編號 | 字符 | 編號 | 字符 |
---|---|---|---|---|---|---|---|
0 | A | 16 | Q | 32 | g | 48 | w |
1 | B | 17 | R | 33 | h | 49 | x |
2 | C | 18 | S | 34 | i | 50 | y |
3 | D | 19 | T | 35 | j | 51 | z |
4 | E | 20 | U | 36 | k | 52 | 0 |
5 | F | 21 | V | 37 | l | 53 | 1 |
6 | G | 22 | W | 38 | m | 54 | 2 |
7 | H | 23 | X | 39 | n | 55 | 3 |
8 | I | 24 | Y | 40 | o | 56 | 4 |
9 | J | 25 | Z | 41 | p | 57 | 5 |
10 | K | 26 | a | 42 | q | 58 | 6 |
11 | L | 27 | b | 43 | r | 59 | 7 |
12 | M | 28 | c | 44 | s | 60 | 8 |
13 | N | 29 | d | 45 | t | 61 | 9 |
14 | O | 30 | e | 46 | u | 62 | + |
15 | P | 31 | f | 47 | v | 63 | / |
下面我們來看下Base64算法實現的大致步驟:
- 將給定的字符串以字符為單位轉換為對應的字符編碼(如ASCII碼);
- 將獲得的字符編碼轉換為二進制碼;
- 對獲得的二進制碼做分組轉換操作,每3個8位二進制碼為一組,轉換為每4個6位二進制碼為一組(不足6位時地位補0).這是一個分組變化的過程,3個8位二進制碼和4個6位二進制碼的長度都是24位;
- 對獲得的4個6位二進制補位,向6位二進制碼添加2位高位0,組成4個8位二進制碼;
- 將獲得的4個8位二進制碼轉換位10進制碼;
- 將獲得的十進制碼轉換位Base64字符表中對應的字符;
ASCII碼字符編碼,
比如,我們對A進行Base64編碼:
??最終生成的編碼中有了兩個等號,這是因為原文的二進制碼不足24位,最后轉換為十進制碼時也不足4項,這時就需要用等號補位;
??經Base64編碼后的字符串最多只會有2個等號,這是因為 余數 = 原文字節數 MOD 3,所以余數只能時0,1,2。通常判別一個字符串是不是Base64編碼的第一步操作就是判斷這個字符串末尾是不是有等號。這同時也說明,Base64編碼后的字符串是以4個字符為單位,其長度只能是4個字符的整數倍。
非ASCII碼字符編碼
??ASCII碼可以表示十進制范圍為0到127的字符,對應二進制范圍是00000000~01111111,ASCII碼包含了阿拉伯數字,大小寫英文字母和一些控制符,但卻沒有包含中文,因此有了GB2312,GBK和UTF-8等編碼。GBK,GB2312用2個字節來表示一個漢字,UTF-8則用3個字節來表示一個漢字。
例如:對 密
這個字以UTF-8的形式進行Base64編碼;
最終
密
的Base64編碼是 5a+G
。當然,如果我們不使用UTF-8,而是使用GBK來進行編碼,那編碼后的結果就不是5a+G了。
Java中Base64編碼使用
??JDK中Base64的實現在JDK1.7之前是沒有對外的公共接口的,只有一個非標準實現,位于sun.misc包中,提供BASE64Encoder類和BASE64Decoder類。由于是不對外,所以不建議使用,并且后續JDK版本可能會去掉對這兩個類的支持。
??所以說在JDK1.8之前,如果我們要對數據進行Base64編碼,一般會借助于第三方的實現,比如Apache Commons包或者Google Guava包。
??但在JDK1.8之后,這個問題就不復存在了。JDK1.8提供了一個完整的類用于實現Base64編碼解碼,這個類是 java.util.Base64
。以后我們如果需要對Base64編碼解碼,就可以使用這個類來完成了。
Base64
我們可以查看下Base64的官方API:https://docs.oracle.com/javase/8/docs/api/
Base64提供了一套用于獲取編碼器和解碼器的靜態方法,其中大致分為三類:
- Basic編碼器
- URL和文件安全編碼器
- MIME編碼器
Basic編碼
Basic編碼是標準的Base64編碼,用于處理常規的需求,使用特別簡單:
public static void main(String[] args) throws UnsupportedEncodingException {
String string = "密";
System.out.println("old string: " + string);
String base64 = Base64.getEncoder().encodeToString(string.getBytes("UTF-8"));
System.out.println("base64 decode: " + base64);
byte[] bytes = Base64.getDecoder().decode(base64);
System.out.println("base64 encode: " + new String(bytes, "UTF-8"));
}
output:
old string: 密
base64 decode: 5a+G
base64 encode: 密
URL編碼
URL編碼和Basic編碼有些不同,主要是URL中反斜杠 /
有特殊的含義,直接編碼會不太安全,所以URL編碼會使用下劃線 _
來替代 /
。
比如我們直接編碼:
String string = "http://www.google.com/index.html?pageNum=1&pageSize=10";
System.out.println("old string: " + string);
String base64 = Base64.getEncoder().encodeToString(string.getBytes("UTF-8"));
System.out.println("base64 decode: " + base64);
output:
old string: http://www.google.com/index.html?pageNum=1&pageSize=10
base64 decode: aHR0cDovL3d3dy5nb29nbGUuY29tL2luZGV4Lmh0bWw/cGFnZU51bT0xJnBhZ2VTaXplPTEw
所以,我們可以使用Base64中的 Base64.getUrlEncoder()
來獲取URL編碼器,然后再進一步操作。
String base64 = Base64.getUrlEncoder().encodeToString(string.getBytes("UTF-8"));
System.out.println("base64 decode: " + base64);
byte[] bytes = Base64.getUrlDecoder().decode(base64);
output:
old string: http://www.google.com/index.html?pageNum=1&pageSize=10
base64 decode: aHR0cDovL3d3dy5nb29nbGUuY29tL2luZGV4Lmh0bWw_cGFnZU51bT0xJnBhZ2VTaXplPTEw
base64 encode: http://www.google.com/index.html?pageNum=1&pageSize=10
MIME編碼
MIME編碼適用于MIME格式數據,編碼后每行的輸出不超過76個字符,結束符號為\r\n。所謂MIME格式就是文件的表達形式,比如 image/png
,video/mp4
等。
打印的結果大致如下:
NDU5ZTFkNDEtMDVlNy00MDFiLTk3YjgtMWRlMmRkMWEzMzc5YTJkZmEzY2YtM2Y2My00Y2Q4LTk5
ZmYtMTU1NzY0MWM5Zjk4ODA5ZjVjOGUtOGMxNi00ZmVjLTgyZjctNmVjYTU5MTAxZWUyNjQ1MjJj
NDMtYzA0MC00MjExLTk0NWMtYmFiZGRlNDk5OTZhMDMxZGE5ZTYtZWVhYS00OGFmLTlhMjgtMDM1
ZjAyY2QxNDUyOWZiMjI3NDctNmI3OC00YjgyLThiZGQtM2MyY2E3ZGNjYmIxOTQ1MDVkOGQtMzIz
Yi00MDg0LWE0ZmItYzkwMGEzNDUxZTIwOTllZTJiYjctMWI3MS00YmQzLTgyYjUtZGRmYmYxNDA4
Mjg3YTMxZjMxZmMtYTdmYy00YzMyLTkyNzktZTc2ZDc5ZWU4N2M5ZDU1NmQ4NWYtMDkwOC00YjIy
LWIwYWItMzJiYmZmM2M0OTBm
同樣,獲取該編碼或解碼器也很簡單:
Base64.getMimeEncoder();
Base64.getMimeDecoder();
本文主要參考自:
https://docs.oracle.com/javase/8/docs/api/
Base64 encoding and decoding in Java 8