? Base64是網絡上最常見的用于加密傳輸8Bit字節代碼的編碼方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的詳細規范。Base64要求把每三個8Bit的字節轉換為四個6Bit的字節(3*8 = 4*6 = 24),然后把6Bit再添兩位高位0,組成四個8Bit的字節,也就是說,轉換后的字符串理論上將要比原來的長1/3。
這樣說會不會太抽象了?不怕,我們來看一個例子:
轉換前 | aaaaaabb | ccccdddd | eeffffff | | 轉換后 | 00aaaaaa | 00bbcccc | 00ddddee | 00ffffff |
????應該很清楚了吧?上面的三個字節是原文,下面的四個字節是轉換后的Base64編碼,其前兩位均為0。
|
|
????轉換后,我們用一個碼表來得到我們想要的字符串(也就是最終的Base64編碼),這個表是這樣的:(摘自RFC2045)
????????????????????????????Table 1: The Base64 Alphabet
??????Value Encoding??Value Encoding??Value Encoding??Value Encoding
?????????? 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???????? ???????(pad) =
??????????15 P????????????????32 g??????????????????49 x
??????????16 Q????????????????33 h??????????????????50 y
讓我們再來看一個實際的例子,加深印象!
轉換前 |
10101101 |
10111010 |
01110110 |
|
轉換后 |
00101011 |
00011011 |
00101001 |
00110110 |
十進制 |
43 |
27 |
41 |
54 |
對應碼表中的值 |
r |
b |
p |
2 |
所以上面的24位編碼,編碼后的Base64值為 rbp2
解碼同理,把 rbq2 的二進制位連接上再重組得到三個8位值,得出原碼。
(解碼只是編碼的逆過程,在此我就不多說了,另外有關MIME的RFC還是有很多的,如果需要詳細情況請自行查找。)
下面的Base64編碼/解碼程序來自網上。
一、用SUN的API解碼和編碼
import java.io.*;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class Base64
{
public static void main(String[] args) {
if (args.length == 2) {
String string = Base64.encode(args[0]);
Base64.decode(string, args[1]);
} else
System.out.println("usage: java Base64 inputFile outputFile");
}
public static String encode(String fileName) {
String string = null;
try {
InputStream in = new FileInputStream(fileName);
// in.available()返回文件的字節長度
byte[] bytes = new byte[in.available()];
// 將文件中的內容讀入到數組中
in.read(bytes);
string = new BASE64Encoder().encode(bytes);
in.close();
} catch (FileNotFoundException fe) {
fe.printStackTrace();
} catch(IOException ioe) {
ioe.printStackTrace();
}
return string;
}
public static void decode(String string, String fileName) {
try {
// 解碼,然后將字節轉換為文件
byte[] bytes = new BASE64Decoder().decodeBuffer(string);
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
byte[] buffer = new byte[1024];
FileOutputStream out = new FileOutputStream(fileName);
int bytesum = 0;
int byteread = 0;
while ((byteread = in.read(buffer)) != -1) {
bytesum += byteread;
out.write(buffer, 0, byteread);
}
} catch(IOException ioe) {
ioe.printStackTrace();
}
}
}
二、
/* @author CuCuChen
* @version $Id$
*/
import java.io.*;
class Base64Helper {
//從文本文件對象中讀取內容并轉換為字符數組
public static char[] readChars(File file)
{
CharArrayWriter caw = new CharArrayWriter();
try
{
Reader fr = new FileReader(file);
Reader in = new BufferedReader(fr);
int count = 0;
char[] buf = new char[16384];
while ((count=in.read(buf)) != -1) {
if (count > 0) caw.write(buf, 0, count);
}
in.close();
}
catch (Exception e) { e.printStackTrace(); }
return caw.toCharArray();
}
//從字符串對象中讀取內容并轉換為字符數組
public static char[] readChars(String string)
{
CharArrayWriter caw = new CharArrayWriter();
try
{
Reader sr = new StringReader(string.trim());
Reader in = new BufferedReader(sr);
int count = 0;
char[] buf = new char[16384];
while ((count=in.read(buf)) != -1) {
if (count > 0) caw.write(buf, 0, count);
}
in.close();
}
catch (Exception e) { e.printStackTrace(); }
return caw.toCharArray();
}
//從二進制文件對象中讀取內容并轉換為字節數組
public static byte[] readBytes(File file)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try
{
InputStream fis = new FileInputStream(file);
InputStream is = new BufferedInputStream(fis);
int count = 0;
byte[] buf = new byte[16384];
while ((count=is.read(buf)) != -1) {
if (count > 0) baos.write(buf, 0, count);
}
is.close();
}
catch (Exception e) { e.printStackTrace(); }
return baos.toByteArray();
}
//寫字節數組內容到二進制文件
public static void writeBytes(File file, byte[] data) {
try {
OutputStream fos = new FileOutputStream(file);
OutputStream os = new BufferedOutputStream(fos);
os.write(data);
os.close();
}
catch (Exception e) { e.printStackTrace(); }
}
//寫字符數組內容到文本文件
public static void writeChars(File file, char[] data) {
try {
Writer fos = new FileWriter(file);
Writer os = new BufferedWriter(fos);
os.write(data);
os.close();
}
catch (Exception e) { e.printStackTrace(); }
}
}
public class Base64{
//編碼文件對象所指的文件
static public char[] encode(File file){
if (!file.exists()) {
System.err.println("錯誤:文件不存在!");
return null;
}
return encode(Base64Helper.readBytes(file));
}
//編碼文件名所指的文件
static public char[] encode(String filename){
File file = new File(filename);
if (!file.exists()) {
System.err.println("錯誤:文件“"+filename+"”不存在!");
return null;
}
return encode(Base64Helper.readBytes(file));
}
//編碼傳入的字節數組,輸出編碼后的字符數組
static public char[] encode(byte[] data)
{
char[] out = new char[((data.length + 2) / 3) * 4];
//
// 對字節進行Base64編碼,每三個字節轉化為4個字符.
// 輸出總是能被4整除的偶數個字符
//
for (int i=0, index=0; i< data.length; i+=3, index+=4) {
boolean quad = false;
boolean trip = false;
int val = (0xFF & (int) data[i]);
val <<= 8;
if ((i+1) < data.length) {
val |= (0xFF & (int) data[i+1]);
trip = true;
}
val <<= 8;
if ((i+2) < data.length) {
val |= (0xFF & (int) data[i+2]);
quad = true;
}
out[index+3] = alphabet[(quad? (val & 0x3F): 64)];
val >>= 6;
out[index+2] = alphabet[(trip? (val & 0x3F): 64)];
val >>= 6;
out[index+1] = alphabet[val & 0x3F];
val >>= 6;
out[index+0] = alphabet[val & 0x3F];
}
return out;
}
static public byte[] decode(char[] data)
{
// 程序中有判斷如果有回車、空格等非法字符,則要去掉這些字符
// 這樣就不會計算錯誤輸出的內容
int tempLen = data.length;
for( int ix=0; ix< data.length; ix++ )
{
if( (data[ix] > 255) || codes[ data[ix] ] < 0 )
--tempLen; // 去除無效的字符
}
// 計算byte的長度
// -- 每四個有效字符輸出三個字節的內容
// -- 如果有額外的3個字符,則還要加上2個字節,
// 或者如果有額外的2個字符,則要加上1個字節
int len = (tempLen / 4) * 3;
if ((tempLen % 4) == 3) len += 2;
if ((tempLen % 4) == 2) len += 1;
byte[] out = new byte[len];
int shift = 0;
int accum = 0;
int index = 0;
// 一個一個字符地解碼(注意用的不是tempLen的值進行循環)
for (int ix=0; ix< data.length; ix++)
{
int value = (data[ix]>255)? -1: codes[ data[ix] ];
if ( value >= 0 ) // 忽略無效字符
{
accum <<= 6;
shift += 6;
accum |= value;
if ( shift >= 8 )
{
shift -= 8;
out[index++] =
(byte) ((accum >> shift) & 0xff);
}
}
}
//如果數組長度和實際長度不符合,那么拋出錯誤
if( index != out.length)
{
throw new Error("數據長度不一致(實際寫入了 " + index + "字節,但是系統指示有" + out.length + "字節)");
}
return out;
}
//
// 用于編碼的字符
//
static private char[] alphabet ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();
//
// 用于解碼的字節(0-255)
//
static private byte[] codes = new byte[256];
static {
for (int i=0; i<256; i++) codes[i] = -1;
for (int i = 'A'; i <= 'Z'; i++) codes[i] = (byte)( i - 'A');
for (int i = 'a'; i <= 'z'; i++) codes[i] = (byte)(26 + i - 'a');
for (int i = '0'; i <= '9'; i++) codes[i] = (byte)(52 + i - '0');
codes['+'] = 62;
codes['/'] = 63;
}
public static void main (String [] args){
String key = new String("Spider");
byte[] a = key.getBytes();
char[] b = Base64.encode(a) ;
System.out.println(new String(b));
//for(int i=0;i< b.length;i++){
// System.out.println(b[i]);
//}
byte[] c = Base64. decode(b);
System.out.println(new String(c));
}
}
運行結果:
C:\java>java Base64
U3BpZGVy
Spider