用Base64編碼與解碼
Base64是網絡上最常見的用于加密傳輸8Bit字節代碼的編碼方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的詳細規范。Base64要求把每三個8Bit的字節轉換為四個6Bit的字節(3*8 = 4*6 = 24),然后把6Bit再添兩位高位0,組成四個8Bit的字節,也就是說,轉換后的字符串理論上將要比原來的長1/3。 這樣說會不會太抽象了?不怕,我們來看一個例子:
????應該很清楚了吧?上面的三個字節是原文,下面的四個字節是轉換后的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
posted on 2006-11-08 08:34 都市淘沙者 閱讀(1041) 評論(0) 編輯 收藏 所屬分類: Java Basic/Lucene/開源資料