Base64(基底64)是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。3个字节相当于24个比特,对应于4个Base64单元,即3个字节可由4个可打印字符来表示。在Base64中的可打印字符包括字母
A-Z
、a-z
、数字0-9
,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。一些如uuencode的其他编码方法,和之后BinHex的版本使用不同的64字符集来代表6个二进制数字,但是不被称为Base64。
Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据,包括MIME的电子邮件及XML的一些复杂数据。
关于Base64我们要明白的最重要的一点就是,他是一中编码格式,而不是加密算法。
Base64编码索引表:
Base64的出现是为了让一些二进制数据可视化并且能够进行传输,存储。例如图片、音频、视频等。
Base64 会经常用作一个简单的“加密”来保护某些数据,而真正的加密通常都比较繁琐。
Base64将3个字节变成4个字节。
如果要编码的字节数不能被3整除,最后会多出1个或2个字节,那么可以使用下面的方法进行处理:先使用0字节值在末尾补足,使其能够被3整除,然后再进行Base64的编码。在编码后的Base64文本后加上一个或两个=号,代表补足的字节数。也就是说,当最后剩余两个八位(待补足)字节(2个byte)时,最后一个6位的Base64字节块有四位是0值,最后附加上两个等号;如果最后剩余一个八位(待补足)字节(1个byte)时,最后一个6位的base字节块有两位是0值,最后附加一个等号。
下面我们用Java实现Base64算法:
首先我们要将Base64的对照表存进一个char型数组中去,为了之后要用的时候可以直接查表打印。
public static char[] base64 = {
'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', '+', '/'
};
以下是编码的代码:
private static List encodeToBase64(byte[] bytes) {
//记录编码的字节数被3除的余数
int num = bytes.length % 3;
List stringList = new ArrayList();
int v = 0;
for (int i = 2; i < bytes.length; i += 3) {
//用V来接收拼接后的数,由于byte数组中每一个是8位的二进制数,三个拼起来正好是24位
v = ((bytes[i - 2] & 0xff) << 16) | ((bytes[i - 1] & 0xff) << 8) | (bytes[i] & 0xff);
//在将v与0x3f进行&运算,每次取到六位,将其分成4组
//与0x3f进行&运算,是因为0x3f的二进制码是0011 1111,中间包含六个1,只有在全一的时候才会为1,所以值取到了最后六位
int d0 = v & 0x3f;
int d1 = v >>> 6 & 0x3f;//>>>为无符号的位运算
int d2 = v >>> 12 & 0x3f;
int d3 = v >>> 18 & 0x3f;
//将取得的4组6位数据查表后存入List中
stringList.add(String.valueOf(base64[d3]));
stringList.add(String.valueOf(base64[d2]));
stringList.add(String.valueOf(base64[d1]));
stringList.add(String.valueOf(base64[d0]));
}
//下面的操作是当编码的字节数不能被3整除时,在末尾添加等于号
if (num > 1) {
v = ((bytes[bytes.length - 2] & 0xff) << 16) | ((bytes[bytes.length - 1] & 0xff) << 8);
int d1 = v >>> 6 & 0x3f;
int d2 = v >>> 12 & 0x3f;
int d3 = v >>> 18 & 0x3f;
stringList.add(String.valueOf(base64[d3]));
stringList.add(String.valueOf(base64[d2]));
stringList.add(String.valueOf(base64[d1]));
stringList.add("=");
}
if (num == 1) {
v = ((bytes[bytes.length - 1] & 0xff) << 16);
int d2 = v >>> 12 & 0x3f;
int d3 = v >>> 18 & 0x3f;
stringList.add(String.valueOf(base64[d3]));
stringList.add(String.valueOf(base64[d2]));
stringList.add("=");
stringList.add("=");
}
//输出编码后结果
System.out.print("Base64 编码后:");
for (String s : stringList) {
System.out.print(s);
}
System.out.println();
return stringList;
}
相对编码来说,解码会更加简单些,代码如下:
private static void decode(String string) {
byte[] b = new byte[string.length()];
char[] ch = string.toCharArray();
int n = 0;
//遍历Base64表获取下标并存入byte数组
for (char c : ch) {
for (int i = 0; i < base64.length; i++) {
if (c == base64[i]) {
b[n] = (byte) i;
n++;
}
}
}
int v = 0;
byte[] bytes = new byte[string.length() - 1];
int num = 0;
//将4组合并,并且分为3组每组8位
for (int i = 0; i < b.length; i += 4) {
v = ((b[i] & 0xff) << 18) | ((b[i + 1] & 0xff) << 12) | (b[i + 2] & 0xff) << 6 | (b[i + 3] & 0xff);
int d0 = v & 0xff;
int d1 = v >>> 8 & 0xff;
int d2 = v >>> 16 & 0xff;
bytes[num] = (byte) d2;
bytes[num + 1] = (byte) d1;
bytes[num + 2] = (byte) d0;
num += 3;
}
//去除byte数组末尾的0,末尾有0才去除
if (bytes[bytes.length - 1] == 0){
try {
int length = 0;
for (int i = 0; i < bytes.length; ++i) {
if (bytes[i] == 0) {
length = i;
break;
}
}
String str1 = new String(bytes,0,length);
System.out.println("字符串 "+string+" Base64 解码后:"+str1);
} catch (Exception e) {
e.printStackTrace();
}
}else{
String s1 = new String(bytes);
System.out.println("字符串 "+string+" Base64 解码后:"+s1);
}
}
最后我们只要调用方法就好了。
测试用例:
原始字符串:丢
Base64 编码后:5Lii
再用 Base64 解码后:丢
原始字符串:丢15as
Base64 编码后:5LiiMTVhcw==
再用 Base64 解码后:丢15as
想了解更详细的介绍可以点击链接:Base64。
如果有不明白的地方也可以私信我哦~