本文為原創,如需轉載,請注明作者和出處,謝謝!
Base64編碼的原理是按bit將每6個bit轉換成Base64編碼表中的相應字符。下面是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. 最后只剩下2個bit。
2. 最后只剩下4個bit。
對于這兩種情況,需要在后面補0,如下面的兩個字節:
11011001 11011101
在轉換上面的字節時,最后會剩下4個bit。也就是1101,這時需要在后面補0,也就是變成了110100。如果后面補一對0,轉換結果后面加一個“=”,如果補兩對0,加兩個“=”,也就是總共的bit數除3的余數為1,則加一個“=”,余數為2,加兩個“=”。上面的兩個字節是16個bit,除3的余數是1,因此,需要補一個“=”,也就是將這兩個字節分成如下三組:
110110 011101 110100
其中110100后面兩個0是補的,因此,查找上面的base64編碼表可將這兩個字節轉換成如下的Base64編碼:
2d0=
下面我們來實現這個算法。算法的基本原理如下:
由于每次轉換都需要6個bit,而這6個bit可能都來自一個字節,也可以來自前后相臨的兩個字節。定義兩個變量:prevByteBitCount和nextByteBitCount,這兩個變量分別表述從前一個和后一個節字取得的bit數。如果prevByteBitCount為0,表示6個bit全部來自下一個字節的高6位。如果nextByteBitCount = 0,表示6個bit全部來自前一個字節的低6位。最后通過適當的移位獲得所需要的6個bit,再在上面的base64編碼表中查找相應的字符。算法的實現代碼如下:
public static String encoder(byte[] bytes)
{
StringBuilder result = new StringBuilder();
String base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// prevByteBitCount表示從前一個字節取得的bit數,nextByteBitCount表示從后一個字節取得的bit數
int prevByteBitCount = 0, nextByteBitCount = 6;
// i表示當前的數組索引,n表示已經處理的位數
int i = 0, n = 0;
// byteCount表示總的位數
int byteCount = 8 * bytes.length;
byte b = 0;
while (true)
{
// 處理從前后兩個字節取得位數的情況
if (prevByteBitCount > 0 && nextByteBitCount > 0)
{
// 將前一個字節的低位向左移nextByteBitCount個bit,并使下一個字節的高位(nextByteBitCount指定的位數)右移到字節的最低位,
// 然后將兩個位移結果進行邏輯或,也就是將從前一個字節和后一個字節取得的相應的bit合并為一個字節的低位
b = (byte) (((0xff & bytes[i]) << nextByteBitCount) | ((0xff & bytes[i + 1]) >> (8 - nextByteBitCount)));
// 將邏輯或后的結果的最高兩個bit置成0
b = (byte) (b & 0x3f);
prevByteBitCount = 8 - nextByteBitCount;
nextByteBitCount = 6 - prevByteBitCount;
}
// 處理從后一個字節取得高6位的情況
else if (prevByteBitCount == 0)
{
// 后一個字節的高6位右移動低6位
b = (byte) ((0xff & bytes[i]) >> (8 - nextByteBitCount));
// 處理后面的位時,就是從前一個字節取2個bit,從后一個字字取4個bit
prevByteBitCount = 2;
nextByteBitCount = 4;
}
// 處理從前一個字節取得低6位的情況
else if (nextByteBitCount == 0)
{
// 將前一個字節的最高兩個bit置成0
b = (byte) (0x3f & bytes[i]);
// 處理后面的位時,從后一個字節取6個bit
prevByteBitCount = 0;
nextByteBitCount = 6;
}
result.append(base64.charAt(b));
n += 6;
i = n / 8;
int remainBitCount = byteCount - n;
if (remainBitCount < 6)
{
// 將剩余的bit補0后,仍然需要在base64編碼表中查找相應的字符,并添加到結果字符串的最后
if (remainBitCount > 0)
{
b = bytes[bytes.length - 1];
b = (byte) (0x3f & (b << (6 - remainBitCount)));
result.append(base64.charAt(b));
}
break;
}
}
// 如果總bit數除3的余數為1,加一個“=”,為2,加兩個“=”
n = byteCount % 3;
for (i = 0; i < n; i++)
result.append("=");
return result.toString();
}
最后可以使用下面的代碼來驗證encoder方法的正確性:
String s = "中華人民共和國";
byte[] bytes = s.getBytes("UTF-8");
System.out.println(encoder(bytes));
// 使用jdk提供的base64轉換類對字節數組進行base64編碼
sun.misc.BASE64Encoder base64Encoder = new sun.misc.BASE64Encoder();
System.out.println(base64Encoder.encode(bytes));
上面的代碼的執行結果如下:
5Lit5Y2O5Lq65rCR5YWx5ZKM5Zu9
5Lit5Y2O5Lq65rCR5YWx5ZKM5Zu9
新浪微博:http://t.sina.com.cn/androidguy 昵稱:李寧_Lining