Java1.8-實(shí)現(xiàn)Base64編碼解碼

概述

首先,我們先來說下什么是Base64編碼,然后再來學(xué)習(xí)下Java中Base64編碼的使用。

歷史

??Base64算法最早是為了解決電子郵件傳輸?shù)膯栴}的,早先的郵件傳輸協(xié)議中只支持ASCII碼傳遞,如果要傳輸二進(jìn)制文件,如圖片和視頻,是無法傳輸?shù)?,而BASE64可以將二進(jìn)制文件內(nèi)容編碼成為只包含ASCII碼的內(nèi)容,這樣就可以傳輸了。
??Base64算法大家常常說成是加密算法,但準(zhǔn)確的來說,Base64不是一種加密算法,只能算是一種基于64個字符的編碼算法。

??它有一個字符映射表,每個字符映射了一個十進(jìn)制編碼,共映射了64個字符。Base64將給定的數(shù)據(jù)經(jīng)二進(jìn)制轉(zhuǎn)換后與字符映射表相對應(yīng),得到所謂的密文;映射表如下,映射表的最后是一個等號,是作為補(bǔ)位符用來補(bǔ)位的。

編號 字符 編號 字符 編號 字符 編號 字符
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算法實(shí)現(xiàn)的大致步驟:

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

比如,我們對A進(jìn)行Base64編碼:


ASCII碼字符編碼.png

??最終生成的編碼中有了兩個等號,這是因?yàn)樵牡亩M(jìn)制碼不足24位,最后轉(zhuǎn)換為十進(jìn)制碼時也不足4項,這時就需要用等號補(bǔ)位;

??經(jīng)Base64編碼后的字符串最多只會有2個等號,這是因?yàn)?余數(shù) = 原文字節(jié)數(shù) MOD 3,所以余數(shù)只能時0,1,2。通常判別一個字符串是不是Base64編碼的第一步操作就是判斷這個字符串末尾是不是有等號。這同時也說明,Base64編碼后的字符串是以4個字符為單位,其長度只能是4個字符的整數(shù)倍。

非ASCII碼字符編碼

??ASCII碼可以表示十進(jìn)制范圍為0到127的字符,對應(yīng)二進(jìn)制范圍是00000000~01111111,ASCII碼包含了阿拉伯?dāng)?shù)字,大小寫英文字母和一些控制符,但卻沒有包含中文,因此有了GB2312,GBK和UTF-8等編碼。GBK,GB2312用2個字節(jié)來表示一個漢字,UTF-8則用3個字節(jié)來表示一個漢字。

例如:對 這個字以UTF-8的形式進(jìn)行Base64編碼;

非ASCII碼字符編碼.png

最終的Base64編碼是 5a+G。當(dāng)然,如果我們不使用UTF-8,而是使用GBK來進(jìn)行編碼,那編碼后的結(jié)果就不是5a+G了。

Java中Base64編碼使用

??JDK中Base64的實(shí)現(xiàn)在JDK1.7之前是沒有對外的公共接口的,只有一個非標(biāo)準(zhǔn)實(shí)現(xiàn),位于sun.misc包中,提供BASE64Encoder類和BASE64Decoder類。由于是不對外,所以不建議使用,并且后續(xù)JDK版本可能會去掉對這兩個類的支持。

??所以說在JDK1.8之前,如果我們要對數(shù)據(jù)進(jìn)行Base64編碼,一般會借助于第三方的實(shí)現(xiàn),比如Apache Commons包或者Google Guava包。

??但在JDK1.8之后,這個問題就不復(fù)存在了。JDK1.8提供了一個完整的類用于實(shí)現(xiàn)Base64編碼解碼,這個類是 java.util.Base64。以后我們?nèi)绻枰獙ase64編碼解碼,就可以使用這個類來完成了。

Base64

我們可以查看下Base64的官方API:https://docs.oracle.com/javase/8/docs/api/
Base64提供了一套用于獲取編碼器和解碼器的靜態(tài)方法,其中大致分為三類:

  • Basic編碼器
  • URL和文件安全編碼器
  • MIME編碼器
Basic編碼

Basic編碼是標(biāo)準(zhǔn)的Base64編碼,用于處理常規(guī)的需求,使用特別簡單:

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編碼器,然后再進(jìn)一步操作。

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格式數(shù)據(jù),編碼后每行的輸出不超過76個字符,結(jié)束符號為\r\n。所謂MIME格式就是文件的表達(dá)形式,比如 image/png,video/mp4等。
打印的結(jié)果大致如下:

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容