Base64编码

什么是Base64编码

首先,我们知道,编码的目的一般是为了数据压缩和数据传输的需要。Base64编码的产生就是因为后者:有些网络传送渠道并不支持所有的字节的传输。Base64编码就是一种将二进制数据映射成一些可打印字符(或逆过来)的映射规则,具体的说是映射到[A-Za-z0-9+/]上。比如将字符"中国"映射成5Lit5Zu9,当然也可将图片或其他文件编码成类似上述的字符。

Base64编码的原理

其次,我们需要知道的是,在计算机的世界里,一切都是由01011...这样的二进制数组成的,包括一个字符串,一张图片或一些其他类型的文件。比如对于一个字符串"中",在Java里,我们可以调用"中".getBytes()来得到"中"对应的字节数组:[-28, -72, -83],再将字节数组中的每个数转换为二进制,连接起来便是其二进制表示了:1110 0100_1011 1000_1010 1101(为了便于阅读,用下滑线将每个字节分开。当然,采用不同的编码形式,得到的字节数组可能不同,此处采用的是utf-8编码)。对于文件,可以从其输入流读中取到。

因为字符集合[A-Za-z0-9+/]长度是64,可以与所有6位长的二进制数一一对应 ,于是Base64编码的做法就是,将待编码的所有二进制位每6位分为一组,然后将每组二进制数映射到字符集合中的一个字符,最后将这些映射的字符依次排列起来便得到了编码结果。当然,待编码的二进制位可能不能被6整除,即最终可能会剩余2个或4个二进制位不能构成一组,这时我们可以在其后添加4或2个0来凑成一组。

比如对于上述的字符串"中",其二进制为:1110 0100_1011 1000_1010 1101,我们每6位组成一组,得到:111001_001011_100010_101101,每组转换为十进制就是:57_11_34_45,在按顺序映射到字符集合[A-Za-z0-9+/]上,便得到其Base64编码为:5Lit。如果最后一组填充了0,则还需在编码后的字符串后加上=符号。

解码的过程就是编码过程的逆过程,这里不再赘述。

Base64编码的实现

下面给出Base64编码的实现(末尾未加=):

public static String base64Encode(String text) {
	if (text == null) {
		return null;
	}
	final String table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
	byte[] textBytes = text.getBytes();
	byte[] keyBytes = key.getBytes();
	int remain = 0, remainBitCount = 0;
	StringBuilder builder = new StringBuilder();
	for (int i = 0; i < textBytes.length; i++) {
		int b = textBytes[i] & 0xFF;
		// 获取b的高(6 - remainBitCount)位
		int hight = b >>> (2 + remainBitCount) & 0xFF;
		// 与上一轮的余留组合成一个字节
		int curr = remain << (6 - remainBitCount) | hight;
		// builder.append(table.charAt(curr));
		builder.append(table.charAt(curr));
		// 剩余b的低(2 + remainBitCount)位
		remain = hight << (2 + remainBitCount) ^ b;
		remainBitCount += 2;
		// 若剩余的位刚好为6位,则进行编码
		if (remainBitCount == 6) {
			builder.append(table.charAt(remain));
			remainBitCount = 0;
			remain = 0;
		}
	}
	if (remainBitCount != 0) {
		// 多出的位到末尾补0凑够6位
		builder.append(table.charAt(remain << (6 - remainBitCount)));
	}
	return builder.toString();
}
public static String base64Decode(String text) {
	if (text == null) {
		 return text;
	}
	byte[] bs = new byte[text.length() * 6 / 8];
	int pos = 0, remain = 0, remainBitCount = 0;
	final String table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
	for (int i = 0; i < text.length(); i++) {
		int code = table.indexOf(text.charAt(i));
		if (remainBitCount + 6 < 8) {
			// 不足一个字节
			remain = remain << 6 | code;
			remainBitCount += 6;
		} else {
			// 足够一个字节,取code的高(8 - remainBitCount)位
			int hight = code >>> (remainBitCount - 2) & 0xFF;
			bs[pos] = (byte) (remain << (8 - remainBitCount) | hight);
			pos++;
			remainBitCount -= 2;
            // 保留剩余的位
			remain = hight << remainBitCount ^ code;
		}
	}
	return new String(bs);
}
posted @ 2016-04-02 22:37  学数学的程序猿  阅读(643)  评论(0编辑  收藏  举报