Base64編碼原理與實(shí)現(xiàn)
本文為原創(chuàng),如需轉(zhuǎn)載,請(qǐng)注明作者和出處,謝謝!
Base64編碼的原理是按bit將每6個(gè)bit轉(zhuǎn)換成Base64編碼表中的相應(yīng)字符。下面是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
在轉(zhuǎn)換到最后一個(gè)字節(jié)時(shí),可能出現(xiàn)如下兩種情況:
1. 最后只剩下2個(gè)bit。
2. 最后只剩下4個(gè)bit。
對(duì)于這兩種情況,需要在后面補(bǔ)0,如下面的兩個(gè)字節(jié):
在轉(zhuǎn)換上面的字節(jié)時(shí),最后會(huì)剩下4個(gè)bit。也就是1101,這時(shí)需要在后面補(bǔ)0,也就是變成了110100。如果后面補(bǔ)一對(duì)0,轉(zhuǎn)換結(jié)果后面加一個(gè)“=”,如果補(bǔ)兩對(duì)0,加兩個(gè)“=”,也就是總共的bit數(shù)除3的余數(shù)為1,則加一個(gè)“=”,余數(shù)為2,加兩個(gè)“=”。上面的兩個(gè)字節(jié)是16個(gè)bit,除3的余數(shù)是1,因此,需要補(bǔ)一個(gè)“=”,也就是將這兩個(gè)字節(jié)分成如下三組:
其中110100后面兩個(gè)0是補(bǔ)的,因此,查找上面的base64編碼表可將這兩個(gè)字節(jié)轉(zhuǎn)換成如下的Base64編碼:
下面我們來(lái)實(shí)現(xiàn)這個(gè)算法。算法的基本原理如下:
由于每次轉(zhuǎn)換都需要6個(gè)bit,而這6個(gè)bit可能都來(lái)自一個(gè)字節(jié),也可以來(lái)自前后相臨的兩個(gè)字節(jié)。定義兩個(gè)變量:prevByteBitCount和nextByteBitCount,這兩個(gè)變量分別表述從前一個(gè)和后一個(gè)節(jié)字取得的bit數(shù)。如果prevByteBitCount為0,表示6個(gè)bit全部來(lái)自下一個(gè)字節(jié)的高6位。如果nextByteBitCount = 0,表示6個(gè)bit全部來(lái)自前一個(gè)字節(jié)的低6位。最后通過(guò)適當(dāng)?shù)囊莆猾@得所需要的6個(gè)bit,再在上面的base64編碼表中查找相應(yīng)的字符。算法的實(shí)現(xiàn)代碼如下:
最后可以使用下面的代碼來(lái)驗(yàn)證encoder方法的正確性:
上面的代碼的執(zhí)行結(jié)果如下:
新浪微博:http://t.sina.com.cn/androidguy 昵稱:李寧_Lining
Base64編碼的原理是按bit將每6個(gè)bit轉(zhuǎn)換成Base64編碼表中的相應(yīng)字符。下面是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
在轉(zhuǎn)換到最后一個(gè)字節(jié)時(shí),可能出現(xiàn)如下兩種情況:
1. 最后只剩下2個(gè)bit。
2. 最后只剩下4個(gè)bit。
對(duì)于這兩種情況,需要在后面補(bǔ)0,如下面的兩個(gè)字節(jié):
11011001 11011101
在轉(zhuǎn)換上面的字節(jié)時(shí),最后會(huì)剩下4個(gè)bit。也就是1101,這時(shí)需要在后面補(bǔ)0,也就是變成了110100。如果后面補(bǔ)一對(duì)0,轉(zhuǎn)換結(jié)果后面加一個(gè)“=”,如果補(bǔ)兩對(duì)0,加兩個(gè)“=”,也就是總共的bit數(shù)除3的余數(shù)為1,則加一個(gè)“=”,余數(shù)為2,加兩個(gè)“=”。上面的兩個(gè)字節(jié)是16個(gè)bit,除3的余數(shù)是1,因此,需要補(bǔ)一個(gè)“=”,也就是將這兩個(gè)字節(jié)分成如下三組:
110110 011101 110100
其中110100后面兩個(gè)0是補(bǔ)的,因此,查找上面的base64編碼表可將這兩個(gè)字節(jié)轉(zhuǎn)換成如下的Base64編碼:
2d0=
下面我們來(lái)實(shí)現(xiàn)這個(gè)算法。算法的基本原理如下:
由于每次轉(zhuǎn)換都需要6個(gè)bit,而這6個(gè)bit可能都來(lái)自一個(gè)字節(jié),也可以來(lái)自前后相臨的兩個(gè)字節(jié)。定義兩個(gè)變量:prevByteBitCount和nextByteBitCount,這兩個(gè)變量分別表述從前一個(gè)和后一個(gè)節(jié)字取得的bit數(shù)。如果prevByteBitCount為0,表示6個(gè)bit全部來(lái)自下一個(gè)字節(jié)的高6位。如果nextByteBitCount = 0,表示6個(gè)bit全部來(lái)自前一個(gè)字節(jié)的低6位。最后通過(guò)適當(dāng)?shù)囊莆猾@得所需要的6個(gè)bit,再在上面的base64編碼表中查找相應(yīng)的字符。算法的實(shí)現(xiàn)代碼如下:
public static String encoder(byte[] bytes)
{
StringBuilder result = new StringBuilder();
String base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// prevByteBitCount表示從前一個(gè)字節(jié)取得的bit數(shù),nextByteBitCount表示從后一個(gè)字節(jié)取得的bit數(shù)
int prevByteBitCount = 0, nextByteBitCount = 6;
// i表示當(dāng)前的數(shù)組索引,n表示已經(jīng)處理的位數(shù)
int i = 0, n = 0;
// byteCount表示總的位數(shù)
int byteCount = 8 * bytes.length;
byte b = 0;
while (true)
{
// 處理從前后兩個(gè)字節(jié)取得位數(shù)的情況
if (prevByteBitCount > 0 && nextByteBitCount > 0)
{
// 將前一個(gè)字節(jié)的低位向左移nextByteBitCount個(gè)bit,并使下一個(gè)字節(jié)的高位(nextByteBitCount指定的位數(shù))右移到字節(jié)的最低位,
// 然后將兩個(gè)位移結(jié)果進(jìn)行邏輯或,也就是將從前一個(gè)字節(jié)和后一個(gè)字節(jié)取得的相應(yīng)的bit合并為一個(gè)字節(jié)的低位
b = (byte) (((0xff & bytes[i]) << nextByteBitCount) | ((0xff & bytes[i + 1]) >> (8 - nextByteBitCount)));
// 將邏輯或后的結(jié)果的最高兩個(gè)bit置成0
b = (byte) (b & 0x3f);
prevByteBitCount = 8 - nextByteBitCount;
nextByteBitCount = 6 - prevByteBitCount;
}
// 處理從后一個(gè)字節(jié)取得高6位的情況
else if (prevByteBitCount == 0)
{
// 后一個(gè)字節(jié)的高6位右移動(dòng)低6位
b = (byte) ((0xff & bytes[i]) >> (8 - nextByteBitCount));
// 處理后面的位時(shí),就是從前一個(gè)字節(jié)取2個(gè)bit,從后一個(gè)字字取4個(gè)bit
prevByteBitCount = 2;
nextByteBitCount = 4;
}
// 處理從前一個(gè)字節(jié)取得低6位的情況
else if (nextByteBitCount == 0)
{
// 將前一個(gè)字節(jié)的最高兩個(gè)bit置成0
b = (byte) (0x3f & bytes[i]);
// 處理后面的位時(shí),從后一個(gè)字節(jié)取6個(gè)bit
prevByteBitCount = 0;
nextByteBitCount = 6;
}
result.append(base64.charAt(b));
n += 6;
i = n / 8;
int remainBitCount = byteCount - n;
if (remainBitCount < 6)
{
// 將剩余的bit補(bǔ)0后,仍然需要在base64編碼表中查找相應(yīng)的字符,并添加到結(jié)果字符串的最后
if (remainBitCount > 0)
{
b = bytes[bytes.length - 1];
b = (byte) (0x3f & (b << (6 - remainBitCount)));
result.append(base64.charAt(b));
}
break;
}
}
// 如果總bit數(shù)除3的余數(shù)為1,加一個(gè)“=”,為2,加兩個(gè)“=”
n = byteCount % 3;
for (i = 0; i < n; i++)
result.append("=");
return result.toString();
}
{
StringBuilder result = new StringBuilder();
String base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// prevByteBitCount表示從前一個(gè)字節(jié)取得的bit數(shù),nextByteBitCount表示從后一個(gè)字節(jié)取得的bit數(shù)
int prevByteBitCount = 0, nextByteBitCount = 6;
// i表示當(dāng)前的數(shù)組索引,n表示已經(jīng)處理的位數(shù)
int i = 0, n = 0;
// byteCount表示總的位數(shù)
int byteCount = 8 * bytes.length;
byte b = 0;
while (true)
{
// 處理從前后兩個(gè)字節(jié)取得位數(shù)的情況
if (prevByteBitCount > 0 && nextByteBitCount > 0)
{
// 將前一個(gè)字節(jié)的低位向左移nextByteBitCount個(gè)bit,并使下一個(gè)字節(jié)的高位(nextByteBitCount指定的位數(shù))右移到字節(jié)的最低位,
// 然后將兩個(gè)位移結(jié)果進(jìn)行邏輯或,也就是將從前一個(gè)字節(jié)和后一個(gè)字節(jié)取得的相應(yīng)的bit合并為一個(gè)字節(jié)的低位
b = (byte) (((0xff & bytes[i]) << nextByteBitCount) | ((0xff & bytes[i + 1]) >> (8 - nextByteBitCount)));
// 將邏輯或后的結(jié)果的最高兩個(gè)bit置成0
b = (byte) (b & 0x3f);
prevByteBitCount = 8 - nextByteBitCount;
nextByteBitCount = 6 - prevByteBitCount;
}
// 處理從后一個(gè)字節(jié)取得高6位的情況
else if (prevByteBitCount == 0)
{
// 后一個(gè)字節(jié)的高6位右移動(dòng)低6位
b = (byte) ((0xff & bytes[i]) >> (8 - nextByteBitCount));
// 處理后面的位時(shí),就是從前一個(gè)字節(jié)取2個(gè)bit,從后一個(gè)字字取4個(gè)bit
prevByteBitCount = 2;
nextByteBitCount = 4;
}
// 處理從前一個(gè)字節(jié)取得低6位的情況
else if (nextByteBitCount == 0)
{
// 將前一個(gè)字節(jié)的最高兩個(gè)bit置成0
b = (byte) (0x3f & bytes[i]);
// 處理后面的位時(shí),從后一個(gè)字節(jié)取6個(gè)bit
prevByteBitCount = 0;
nextByteBitCount = 6;
}
result.append(base64.charAt(b));
n += 6;
i = n / 8;
int remainBitCount = byteCount - n;
if (remainBitCount < 6)
{
// 將剩余的bit補(bǔ)0后,仍然需要在base64編碼表中查找相應(yīng)的字符,并添加到結(jié)果字符串的最后
if (remainBitCount > 0)
{
b = bytes[bytes.length - 1];
b = (byte) (0x3f & (b << (6 - remainBitCount)));
result.append(base64.charAt(b));
}
break;
}
}
// 如果總bit數(shù)除3的余數(shù)為1,加一個(gè)“=”,為2,加兩個(gè)“=”
n = byteCount % 3;
for (i = 0; i < n; i++)
result.append("=");
return result.toString();
}
最后可以使用下面的代碼來(lái)驗(yàn)證encoder方法的正確性:
String s = "中華人民共和國(guó)";
byte[] bytes = s.getBytes("UTF-8");
System.out.println(encoder(bytes));
// 使用jdk提供的base64轉(zhuǎn)換類對(duì)字節(jié)數(shù)組進(jìn)行base64編碼
sun.misc.BASE64Encoder base64Encoder = new sun.misc.BASE64Encoder();
System.out.println(base64Encoder.encode(bytes));
byte[] bytes = s.getBytes("UTF-8");
System.out.println(encoder(bytes));
// 使用jdk提供的base64轉(zhuǎn)換類對(duì)字節(jié)數(shù)組進(jìn)行base64編碼
sun.misc.BASE64Encoder base64Encoder = new sun.misc.BASE64Encoder();
System.out.println(base64Encoder.encode(bytes));
上面的代碼的執(zhí)行結(jié)果如下:
5Lit5Y2O5Lq65rCR5YWx5ZKM5Zu9
5Lit5Y2O5Lq65rCR5YWx5ZKM5Zu9
5Lit5Y2O5Lq65rCR5YWx5ZKM5Zu9
《Android開(kāi)發(fā)完全講義(第2版)》(本書(shū)版權(quán)已輸出到臺(tái)灣)
http://product.dangdang.com/product.aspx?product_id=22741502
《Android高薪之路:Android程序員面試寶典 》http://book.360buy.com/10970314.html
新浪微博:http://t.sina.com.cn/androidguy 昵稱:李寧_Lining
posted on 2009-05-29 19:20 銀河使者 閱讀(4778) 評(píng)論(0) 編輯 收藏 所屬分類: java 、algorithm 、 原創(chuàng)