字符編碼之Base64
博學,切問,近思--詹子知(https://blog.csdn.net/zhiqiangzhan)
1.什麼是Base64.
Base64是網絡上最常見的用於傳輸8Bit字節代碼的編碼方式之一,大家可以查看RFC2045~RFC2049,上麵有MIME的詳細規範。
它采用64個可見的基本字符去傳輸所有信息,因此即使被不同的編碼顛來倒去的編碼解碼也不會造成數據丟失。
索引 | 對應字符 | 索引 | 對應字符 | 索引 | 對應字符 | 索引 | 對應字符 |
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 |
2.Base64的優勢。
- 編碼解碼速度快。
- 具有一定的加密效果。
- 實現簡單。
- 編碼解碼速度快。
3.實現原理。
Base64要求把每三個8Bit的字節轉換為四個6Bit的字節(3*8 = 4*6 = 24),然後把6Bit再添兩位高位0,組成四個8Bit的字節,因此, 轉換後的字節一定會落在區間[0-64)當中,故此可以找到對應基本字符表示此字節,轉換後的字符串理論上將要比原來的長1/3。
我們來看一個例子。
轉換前:10101111 01101011 11001101
轉換後:00101011 00110110 00101111 00001101
編碼轉換規則:
- 用指定的編碼對字符串進行解碼,得到解碼後的字節數組。
- 按照規則把每3個字節轉換為4個Base64基本字符。
- 處理最後的字節
- 剩餘的字節為0,編碼轉換結束。
- 剩餘的字節為1,把當前字節按照規則轉換為Base64前兩個字符,後麵兩位用'='補齊,編碼轉換結束。
- 剩餘的字節為1,把當前字節按照規則轉換為Base64前三個字符,最後一位用'='補齊,編碼轉換結束。
- 得到編碼後的Base64 String。
解碼轉換規則:
- 準備好需要解碼的Base64 String。
- 每4個一組,轉換為對應的3個字節。
- 處理最後剩餘的字符。
- 得到解碼後的字節數組。
4.通用的編碼傳輸解決方案。
- 使用UTF-8對需要傳輸的String進行編碼,得到編碼後的字節數組。
- 用Base64對字節數組進行編碼,得到Base64 String。
- 傳輸編碼後的Base64 String。
- 接收到傳輸到字節數組, 如果是字節數組,用本地編碼對其進行解碼即可,得到Base64 String。
- 用Base64對 Base64 String 進行解碼,得到字節數組。
- 用UTF-8對字節數組進行解碼,得到最終被傳輸的String。
5.Java 實現。
public class Base64 { /** The 64 valid Base64 characters */ private final static char[] BASE64_ALPHABET = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; /** The BASE64 suffix code */ private static final byte SUFFIX_CODE = '='; private Base64() { } /** * Encode a byte array into BASE64 string. * * @param a the source byte array * @return BASE64 string */ public static String encode(byte[] a) { int length = a.length; int numOfGroups = length / 3; int remainingBytes = length - numOfGroups * 3; int resultLength = 4 * ((length + 2) / 3); char[] result = new char[resultLength]; int srcIndex = 0, dstIndex = 0; for (int i = 0; i < numOfGroups; i++) { int byte0 = a[srcIndex++] & 0xff; int byte1 = a[srcIndex++] & 0xff; int byte2 = a[srcIndex++] & 0xff; result[dstIndex++] = BASE64_ALPHABET[byte0 >> 2]; result[dstIndex++] = BASE64_ALPHABET[(byte0 << 4) & 0x30 | (byte1 >> 4)]; result[dstIndex++] = BASE64_ALPHABET[(byte1 << 2) & 0x3c | (byte2 >> 6)]; result[dstIndex++] = BASE64_ALPHABET[byte2 & 0x3f]; } // Process the remaining bytes if (remainingBytes > 0) { int byte0 = a[srcIndex++] & 0xff; result[dstIndex++] = BASE64_ALPHABET[byte0 >> 2]; if (remainingBytes == 1) { result[dstIndex++] = BASE64_ALPHABET[(byte0 << 4) & 0x30]; result[dstIndex++] = SUFFIX_CODE; result[dstIndex++] = SUFFIX_CODE; } else { // remainingBytes == 2; int byte1 = a[srcIndex++] & 0xff; result[dstIndex++] = BASE64_ALPHABET[(byte0 << 4) & 0x30 | (byte1 >> 4)]; result[dstIndex++] = BASE64_ALPHABET[(byte1 << 2) & 0x3f]; result[dstIndex++] = SUFFIX_CODE; } } return new String(result); } /** * Decode a BASE64 string into byte array. * * @param s BASE64 string * @return the original byte array */ public static byte[] decode(String s) { if (s == null || s.length() == 0) { return null; } int length = s.length(); // length must be a multiple of 4 if (length % 4 != 0) { throw new IllegalArgumentException("String length must be a multiple of four."); } int numOfGroups = length / 4; int numOfFullGroups = numOfGroups; int numOfPaddings = 0; if (s.charAt(length - 1) == SUFFIX_CODE) { numOfPaddings++; numOfFullGroups--; if (s.charAt(length - 2) == SUFFIX_CODE) { numOfPaddings++; } } byte[] result = new byte[3 * numOfGroups - numOfPaddings]; int srcIndex = 0, dstIndex = 0; for (int i = 0; i < numOfFullGroups; i++) { int ch0 = getCharIndex(s.charAt(srcIndex++)); int ch1 = getCharIndex(s.charAt(srcIndex++)); int ch2 = getCharIndex(s.charAt(srcIndex++)); int ch3 = getCharIndex(s.charAt(srcIndex++)); result[dstIndex++] = (byte)((ch0 << 2) | (ch1 >> 4)); result[dstIndex++] = (byte)((ch1 << 4) | (ch2 >> 2)); result[dstIndex++] = (byte)((ch2 << 6) | ch3); } if (numOfPaddings != 0) { int ch0 = getCharIndex(s.charAt(srcIndex++)); int ch1 = getCharIndex(s.charAt(srcIndex++)); result[dstIndex++] = (byte)((ch0 << 2) | (ch1 >> 4)); if (numOfPaddings == 1) { int ch2 = getCharIndex(s.charAt(srcIndex++)); result[dstIndex++] = (byte)((ch1 << 4) | (ch2 >> 2)); } } return result; } /** * Get the index of the character in the BASE64_ALPHABET array. * * @param c * @return */ private static int getCharIndex(char c) { if (c >= 'A' && c <= 'Z') { // A-Z: 65-90 return (int) c - 65; } else if (c >= 'a' && c <= 'z') { // a-z: 97-122 return (int) c - 71; } else if (c >= '0' && c <= '9') {// 0-9: 48-57 return (int) c + 4; } else if (c == '+') { return 62; } else if (c == '/') { return 63; } throw new IllegalArgumentException("Character " + c + " is not a BASE64 char"); } public static void main(String[] args) { String buf = encode("中國加油".getBytes()); System.out.println(buf); byte[] result = decode(buf); System.out.println(new String(result)); } }
最後更新:2017-04-02 04:00:25