最近做项目,经常使用base64把byte[]转为String存储,毕竟byte数组不好存储,就对base64的原理好奇,研究了下,发现base64后长度增加了,这个64代表的含义呢,2的6次方,在2进制有特别的含义,毕竟1byte=8bit,这中间有些特殊的设定意义。
这里的abcde是怎么转为YWJjZGU=的呢,可以明显看出转为base64后长度增加了,实际上我们是把String的byte[]转为base64的,末尾的=号是怎么来的。
可以看到JDK9开始的String转为byte[]存储,节约空间,而byte[]{97, 98, 99, 100, 101} 5个字节是怎么转为YWJjZGU=8个字节的。
Base64 编码原理:
码表如上:由A-Z a-z 0-9 + / ,26+26+10+2=64个编码
比如示例的abcde,换算成byte[]为byte[]{97, 98, 99, 100, 101},换算成2进制bit存储如下
10进制 | 97 | 98 | 99 | 100 | 101 |
bit 2进制 | 01100001 | 01100010 | 01100011 | 01100100 | 01100101 |
安装base64编码原则,3个字节为1组,编码为4个字节组,空间扩容1/3
红色表示不足3byte,补0为3byte。对6bit的重新编码数据前面补0凑齐8bit,即一个byte,数据增加8/6,加上不足3byte编码的补0,额外增加了很多数据,但是就可以安装64的码表编码了。相当于把2的8次方数据,按照2的6次方编码,然后补0,按照2的8次方存储。
bit 2进制 | 01100001 | 01100010 | 01100011 | 01100100 | 01100101 | 00000000 |
编码 | 011000 | 010110 | 001001 | 100011 | 011001 | 000110 | 010100 | 000000 | ||||
编码后10进制 | 24 22 9 35 | 25 6 20 = | ||||
查表 | Y W J j | Z G U = |
查表得YWJjZGU=(=表示末尾补0的位数,最多2个==),这里的base64不能用于正则表达式匹配,因为+ /为关键字。
那个如果byte是负数呢,实际上byte为负数,也可以转为2进制,同理进行编码
比如-128,二进制就是10000000,因为计算机只有加法,负数在计算机中是用补码存储
-128就是128的原码1000 0000求反0111 1111 +1 -> 1000 0000
bit 2进制 | 10000000 | 01100010 | 01100011 | 01100100 | 01100101 | 00000000 | ||
编码 | 100000 | 000110 | 001001 | 100011 | 011001 | 000110 | 010100 | 000000 | ||||||
编码后10进制 | 32 6 9 35 | 25 6 20 = | ||||||
查表 | g G J j | Z G U = |
运行程序,跟手动运算结果一样
base64实际上就是对byte数组重新编码,以3个byte为单位,编码成4个byte数据,首位补0,凑齐8bit(1byte数据),对byte进行转为10进制,查表得到base64的字符串,当3个byte凑不齐时,补0 ,base64字符串结尾使用=表示补了几个0。根据base64的编码原则,实际上可以开发其他编码的,比如特殊+ / 可以使用其他符号表示,或者不使用64位。