字符编码之Base64

博学,切问,近思--詹子知(http://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的优势。

  1. 编码解码速度快。
  2. 具有一定的加密效果。
  3. 实现简单。
  4. 编码解码速度快。

3.实现原理。

Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,因此, 转换后的字节一定会落在区间[0-64)当中,故此可以找到对应基本字符表示此字节,转换后的字符串理论上将要比原来的长1/3。

我们来看一个例子。

转换前:10101111 01101011 11001101
转换后:00101011 00110110 00101111 00001101

 

 

编码转换规则:

  1. 用指定的编码对字符串进行解码,得到解码后的字节数组。
  2. 按照规则把每3个字节转换为4个Base64基本字符。
  3. 处理最后的字节
    • 剩余的字节为0,编码转换结束。
    • 剩余的字节为1,把当前字节按照规则转换为Base64前两个字符,后面两位用'='补齐,编码转换结束。
    • 剩余的字节为1,把当前字节按照规则转换为Base64前三个字符,最后一位用'='补齐,编码转换结束。
  4. 得到编码后的Base64 String。


解码转换规则:

  1. 准备好需要解码的Base64 String。
  2. 每4个一组,转换为对应的3个字节。
  3. 处理最后剩余的字符。
  4. 得到解码后的字节数组。

 

4.通用的编码传输解决方案。

  1. 使用UTF-8对需要传输的String进行编码,得到编码后的字节数组。
  2. 用Base64对字节数组进行编码,得到Base64 String。
  3. 传输编码后的Base64 String。
  4. 接收到传输到字节数组, 如果是字节数组,用本地编码对其进行解码即可,得到Base64 String。
  5. 用Base64对 Base64 String 进行解码,得到字节数组。
  6. 用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)); } }  

你可能感兴趣的:(c,加密,String,null,character,byte)