Java1.8-實現Base64編碼解碼

概述

首先,我們先來說下什么是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算法實現的大致步驟:

  1. 將給定的字符串以字符為單位轉換為對應的字符編碼(如ASCII碼);
  2. 將獲得的字符編碼轉換為二進制碼;
  3. 對獲得的二進制碼做分組轉換操作,每3個8位二進制碼為一組,轉換為每4個6位二進制碼為一組(不足6位時地位補0).這是一個分組變化的過程,3個8位二進制碼和4個6位二進制碼的長度都是24位;
  4. 對獲得的4個6位二進制補位,向6位二進制碼添加2位高位0,組成4個8位二進制碼;
  5. 將獲得的4個8位二進制碼轉換位10進制碼;
  6. 將獲得的十進制碼轉換位Base64字符表中對應的字符;
ASCII碼字符編碼,

比如,我們對A進行Base64編碼:


ASCII碼字符編碼.png

??最終生成的編碼中有了兩個等號,這是因為原文的二進制碼不足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編碼;

非ASCII碼字符編碼.png

最終的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/pngvideo/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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,769評論 2 372

推薦閱讀更多精彩內容