Base64概念参见
http://www.ruanyifeng.com/blog/2008/06/base64.html
用一句话来讲base64的话:
base64=64进制=用6位bit表示一个数字
2进制1位
8进制3位
16进制4位
64进制6位
base64编码的核心,就是将一个byte流用6bit的单位分割
科普完了,开始注解代码
public static String encode(byte[] data, int off, int len) {
if (len <= 0) return "";
char[] out = new char[len/3*4+4];//因为是8bit变成6bit,所以刚好3字节对应4个base64字符。所以有len/3*4 ,假设不能整除,至少会生成2个base64的字符,然后根据规范补上两个'=',所以后面+4. 如果是整除的情况,那么后面4个char是用不掉的 注解1
int rindex = off;
int windex = 0;//填充一个char,这里加1,刚好应对注解1整除的情况。
int rest = len-off;
while (rest >= 3) {
// 3个字节作为1组处理
int i = ((data[rindex]&0xff)<<16)
+((data[rindex+1]&0xff)<<8)
+(data[rindex+2]&0xff);
/*
假设这3字节的数据是
xxxxxxxx,xxxxxxxx,xxxxxxxx
我们的目标是
00xxxxxx,00xxxxxx,00xxxxxx,00xxxxxx
step1:
将3字节数据拼接到一块,想到的方法肯定是移位操作. 但是这里的数据有可能是1xxxxxxx这样的情况,移位的时候,会认为是负数,而直接在左边补1.这个是我们所
不希望的。因此先将数据变成正的。所以先执行 byte&0xff.
xxxxxxxx
00000000,00000000,00000000,11111111
得到
00000000,00000000,00000000,xxxxxxxx
然后通过左移操作得到(分别移动16,8位,然后&操作)
00000000,xxxxxxxx,xxxxxxxx,xxxxxxxx
这个数据和我们的目标数据
00xxxxxx,00xxxxxx,00xxxxxx,00xxxxxx
还有点距离,但是回想,我们只需要分别得到6bit的数据,而不是他们拼接好的数据,因此我们可以通过移位分别得到预期的00xxxxxx数据。
我要获取到第一个base64的编码
00000000,aaaaaaaa,bbbbbbbb,cccccccc >>18;向右边移动18位,获取到00000000,00000000,00000000,00aaaaa
我要获取到第二个base64的编码
00000000,aaaaaaaa,bbbbbbbb,cccccccc >>18;向右边移动12位,获取到00000000,00000000,0000aaaa,aaaabbbb,但是我们的预期是00aabbbb,因此我们需要把第6位后的数据置为0,通过&00000000, 00000000,00000000,00111111来得到。就有后面的&0x3f了。
我要获取到第三个base64的编码
同第2步操作,只是右移的位数不同
我要获取到第4个base64的编码
直接&,将第7位以及往左的高位全设为0
然后通过获取到的编码,去对应的数字里将char值设置到目标数组就可以了。
*/
out[windex++] = S_BASE64CHAR[i>>18];
out[windex++] = S_BASE64CHAR[(i>>12)&0x3f];
out[windex++] = S_BASE64CHAR[(i>>6)&0x3f];
out[windex++] = S_BASE64CHAR[i&0x3f];
rindex += 3;
rest -= 3;
}
//下面是不能整除的情况,逻辑和上面差不多。
if (rest == 1) {
int i = data[rindex]&0xff;
out[windex++] = S_BASE64CHAR[i>>2];
out[windex++] = S_BASE64CHAR[(i<<4)&0x3f];
out[windex++] = S_BASE64PAD;
out[windex++] = S_BASE64PAD;
} else if (rest == 2) {
int i = ((data[rindex]&0xff)<<8)+(data[rindex+1]&0xff);
out[windex++] = S_BASE64CHAR[i>>10];
out[windex++] = S_BASE64CHAR[(i>>4)&0x3f];
out[windex++] = S_BASE64CHAR[(i<<2)&0x3f];
out[windex++] = S_BASE64PAD;
}
return new String(out, 0, windex);
}