一、Base64實現轉換原理
它是用64個可打印字符表示二進制所有數據方法。由於2的6次方等於64,所以可以用每6個位元(bit)為一個單元,對應某個可打印字符。我們知道三個字節(byte)有24個位元,就可以剛好對應於4個Base64單元,即3個字節需要用4個Base64的可打印字符來表示。
· 可打印符號:
在Base64中的可打印字符包括字母A-Z、a-z、數字0-9 ,這樣共有62個字符,此外兩個可打印符號在不同的系統中一般有所不同。但是,我們經常所說的Base64另外2個字符是:“+/”。這64個字符,所對應表如下:
編號 字符 編號 字符 編號 字符 編號 字符 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 /
仔細思考一下,你會很快發現,一個問題,就是每次轉換的字節數不一定就是24的整數倍,會出現有多余不足六位的情況,在base64中處理的方法是加零湊夠六位,但是這樣一來在解碼的時候就會出現多余的位 這該怎么辦呢? base64想到了一個很好的解決辦法。這個辦法就是在 base64湊零的同時,還要滿足湊出來的位數是8的倍數,不然就加一個或者兩個特殊的六位 = 符號。為什么是一個或者兩個=符號呢? 因為多個8位轉為6位 只會出現 剩余 2位,4位的情況,剩余2位 只需要一個 表示六位的 = 便可變為8的整數;而剩余4位 需要兩個表示6位的 = 便可以變成16 是8的整數。然后在解密的時候不解析 =即可。
之所以位的總數需要湊成8的倍數,是因為base64主要用於加密后的數據傳送,而在傳送機制中都認為傳送的最小單位是按照字節算的,所以不能出現不是位總數不是8的倍數的情況,在接收到數據后,按順序將6位的base64直接按照順序解密成字節就完成解密了。
· 轉換過程:
① 將三個byte(字節)的數據,先后放入一個24bit(位)的緩沖區中,先來的byte占高位。數據不足 3 byte的話,於緩沖區中剩下的bit用0補足。
② 然后,每次取出6個bit,按照其值選擇 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
中的字符作為編碼后的輸出。不斷進行,直到全部輸入數據轉換完成。
③ 如果最后剩下兩個輸入數據,在編碼結果后加1個“=”;
如果最后剩下一個輸入數據,編碼結果后加2個“=”;
如果沒有剩下任何數據,就什么都不要加,這樣才可以保證資料還原的正確性。
編碼后的數據比原始數據略長,為原來的4/3。
文本 | M | a | n | |||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ASCII編碼 | 77 | 97 | 110 | |||||||||||||||||||||
二進制位 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 |
索引 | 19 | 22 | 5 | 46 | ||||||||||||||||||||
Base64編碼 | T | W | F | u |
M的Ascii碼是77,前六位對應值為19,對應base64字符是T,如此類推。其它字符編碼就可以自動轉換得到!我們看看另外不是剛好是3個字節的情況!
文本(1 Byte) | A | |||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
二進制位 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | ||||||||||||||||
二進制位(補0) | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | ||||||||||||
Base64編碼 | Q | Q | = | = | ||||||||||||||||||||
文本(2 Byte) | B | C | ||||||||||||||||||||||
二進制位 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | x | x | x | x | x | x | ||
二進制位(補0) | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | x | x | x | x | x | x |
Base64編碼 | Q | k | M | = |
二、Base64轉換代碼實現

1 public class Base64Util { 2 private static final char last2byte = (char) Integer.parseInt("00000011", 2); 3 private static final char last4byte = (char) Integer.parseInt("00001111", 2); 4 private static final char last6byte = (char) Integer.parseInt("00111111", 2); 5 private static final char lead6byte = (char) Integer.parseInt("11111100", 2); 6 private static final char lead4byte = (char) Integer.parseInt("11110000", 2); 7 private static final char lead2byte = (char) Integer.parseInt("11000000", 2); 8 private static final char[] encodeTable = new char[] 9 { 10 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 11 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 12 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 13 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' 14 }; 15 16 public Base64Util() { 17 } 18 19 public static String encode(byte[] from) { 20 StringBuilder to = new StringBuilder((int) ((double) from.length * 1.34D) + 3); 21 int num = 0; 22 char currentByte = 0; 23 24 int i; 25 for (i = 0; i < from.length; ++i) { 26 for (num %= 8; num < 8; num += 6) { 27 switch (num) { 28 case 0: 29 currentByte = (char) (from[i] & lead6byte); 30 currentByte = (char) (currentByte >>> 2); 31 case 1: 32 case 3: 33 case 5: 34 default: 35 break; 36 case 2: 37 currentByte = (char) (from[i] & last6byte); 38 break; 39 case 4: 40 currentByte = (char) (from[i] & last4byte); 41 currentByte = (char) (currentByte << 2); 42 if (i + 1 < from.length) { 43 currentByte = (char) (currentByte | (from[i + 1] & lead2byte) >>> 6); 44 } 45 break; 46 case 6: 47 currentByte = (char) (from[i] & last2byte); 48 currentByte = (char) (currentByte << 4); 49 if (i + 1 < from.length) { 50 currentByte = (char) (currentByte | (from[i + 1] & lead4byte) >>> 4); 51 } 52 } 53 54 to.append(encodeTable[currentByte]); 55 } 56 } 57 58 if (to.length() % 4 != 0) { 59 for (i = 4 - to.length() % 4; i > 0; --i) { 60 to.append("="); 61 } 62 } 63 64 return to.toString(); 65 } 66 }