博学,切问,近思--詹子知(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的优势。
- 编码解码速度快。
- 具有一定的加密效果。
- 实现简单。
- 编码解码速度快。
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));
}
}