自定义Base64编码和解码的实现
来源:互联网 发布:凸优化理论与应用 编辑:程序博客网 时间:2024/05/01 01:45
今天把之前实现的Base64的过程写出来,这篇文章的思路是这样的,首先使用自然语言及编程语言来描述Base64编码的过程,然后设计编码和解码的接口函数,最后是代码的实现和测试。
编码和解码是以三个字符为一组来处理的,对于字符串长度不是3的倍数的情况在后面再单独介绍。
例子:s13
编码过程:
1.获得每个字符对应的ASCII码值的二进制形式:01110011 00110001 00110011;
2.将上面的3组8位二进制划分成四组6位二进制的形式:011100 110011 000100 110011;
3.高位补零得到4组8位的二进制的形式:00011100 00110011 00000100 00110011;
4.根据这四组二进制所对应的十进制值到编码表中索引出字符:c z E z。
上述编码过程中需要我们实现的有:将3组8位二进制转换成4组6位二进制,再高位补0;到编码表中索引出对应的字符。
01110011 00110001 00110011截取第一个字节的前6位得到011100,然后第一个字节的最后两位和第二个字节的前四位组合而成110011,再将第二个字节的后4位和第三个字节的前两位组合成000100,最后由第三个字节的后6位得到110011。
先复习下java中移位运算符的知识:<<(左移),>>(带符号右移)和>>>(无符号右移)。
移位运算符是在二进制的基础上对数字进行平移的,由于移动的方向和填充方式的不同分为上面3种。
举个例子:00110011,对应左移2位:00110011<<2,得到11001100,在其低位补0即可。
>>(带符号右移)的运算规则是:低位舍弃,高位补符号位,即正数补0,负数补1。>>>(无符号右移)就是右移对应位数,低位舍弃,高位全部补0。
下面用编程语言来描述编码过程:
1.s13对应的字节为byte[0]:01110011,byte[1]:00110001,byte[2]:00110011。
2.byte[0]无符号右移2位,byte[0]>>>2得到编码后的第一个字节;
3.byte[0]与0x03(00000011)按位与&,这样高6位全为0,再左移4位,将byte[1]>>>4,最后将byte[0]和byte[1]按位或|,得到编码后第二个字节;
4.将byte[1]与0x0f(00001111)按位与&,这样byte[1]的高4位就为0了,这样做的目的是byte[1]的高四位我们现在不需要,然后左移2位,将byte[2]>>>6,因为我们需要byte[2]的低2位。最后将byte[1]和byte[1]进行按位或|操作,得到编码后的第三个字节。
5.将byte[2]的后6位截取,即byte[2]与0x3f按位与&,这样就得到了编码后的第四个字节。
6.根据这四个字节对应的值到编码转换表中查找其所对应的字符。
对于特殊情况:字符串的长度不是3的倍数,剩余1或2个字符。采取的做法是:若剩余1个字符,将该字符转换出2个,若剩余2个字符,将该字符转换出3个,不够补0,最后用=来填充满4个字符。
举个例子:s 对应的二进制为01110011,截取高6位得到00011100,然后最后两位再补零得到一个字节110000,高位补0,即00110000然后补两个=,所以s编码后为cw==。
ss对应的二进制为01110011 01110011,按照之前的规则得到011100 110111 ,0011再通过补0,得到001100,然后填充=,所以ss编码后为c3M=。对于这两种特殊情况,在编程时特殊考虑。
现在我们来考虑编码接口设计(解码与之类似):
public interface Base64 {/** * 将要编码的字符串的字节编码后返回编码后得到字符串 * * @param b:要编码的字符串字节数组 * @return 编码后的字符串 */public abstract String encode(byte[] b);/** * 将三个字节中的第一个截取到前6位,得到编码后的第一字节 * * @param b:三个字节中的第一个 * @return 编码后的第一字节 */public abstract byte firstByte(byte b);/** * 联合三个字节中的第一个和第二个得到编码后的第二个字节 * * @param last_b:第一个字节 next_b:第二个字节 * @return 编码后的第二个字节 */public abstract byte secondByte(byte last_b,byte next_b); /** * 联合三个字节中的第二个和第三个得到编码后的第三个字节 * * @param last_b:第二个字节 next_b:第三个字节 * @return 编码后的第三个字节 */public abstract byte thirdByte(byte last_b,byte next_b);/** * 将三个字节中的第三个字节截取后6位,得到编码后的第四个字节 * * @param b:第三个字节 * @return 编码后的第四个字节 */public abstract byte fourthByte(byte b);/** * 处理特殊情况:字符串长度%3!=0 * */public abstract byte lastOneByte(byte b,int move);}以上函数之间的关系是:外界通过调用encode函数来完成编码,在encode函数内部:首先考虑是否出现特殊情况(字符串长度不是3的倍数),若未出现,就以3个字节为一组来处理字符串:依次调用firstByte,secondByte,thirdByte,fourthByte来得到编码后的四个字节,最后将其转换成编码表中对应的字符即可。若出现特殊情况,在每3个字节为一组在处理完之后,通过lastOneByte来处理剩余的1个或2个字节。
下面先是实现firstByte,secondByte,thirdByte,fourthByte这四个函数,这四个函数就是实现对3个字节的移位运算,来得到4个编码后的字节。
@Overridepublic byte firstByte(byte b) {//对字节b右移2位int r_f=b & 0xff;r_f=r_f >>> 2;return (byte)(r_f & 0x3f);}@Overridepublic byte secondByte(byte last_b, byte next_b) {//取last_b的低2位和next_b的高4位int r_l=last_b & 0xff;int r_n=next_b & 0xff;r_l=last_b & 0x03;//last_b去掉高6位r_l=r_l << 4;//last_b左移4位r_n=r_n >>> 4;//next_b右移4位return (byte)((r_l | r_n) & 0x3f);}@Overridepublic byte thirdByte(byte last_b, byte next_b) {//取last_b的低4位和next_b的高2位int r_l=last_b & 0xff;int r_n=next_b & 0xff;r_l=r_l & 0x0f;//last_b去掉高4位r_l=r_l << 2;//last_b左移2位r_n=r_n >>> 6;//next_b右移6位return (byte)((r_l | r_n) & 0x3f);}@Overridepublic byte fourthByte(byte b) {//取b的低6位int r_b=b & 0xff;r_b=r_b << 2;r_b=r_b >>> 2;return (byte)(r_b & 0x3f);}我们通过firstByte,secondByte,thirdByte,fourthByte这四个函数得到的是四个索引,对应到编码转换表中才得到了编码后的字符。所以我们需要先把编码转换表在代码中实现,下面我们使用一个字节数组来存放字符的ASCII码的二进制。
private static final byte base[] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51,0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62,0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,0x39, 0x2b, 0x2f };在encode函数中,根据firstByte,secondByte,thirdByte,fourthByte得到的值找到byte []中对应的值。
@Overridepublic byte lastOneByte(byte b, int move) {int r_b = b & 0xff;r_b = r_b << move;r_b = r_b >>> 2;return (byte) (r_b & 0x3f);}
@Overridepublic String encode(byte[] b) {StringBuffer sb = new StringBuffer();int len = b.length;int more_len = len % 3;int use_len = len - more_len;byte[] bytes = new byte[4];for (int i = 0; i < use_len; i += 3) {bytes[0] = base[firstByte(b[i])];bytes[1] = base[secondByte(b[i], b[i + 1])];bytes[2] = base[thirdByte(b[i + 1], b[i + 2])];bytes[3] = base[fourthByte(b[i + 2])];sb.append(new String(bytes));}if (more_len == 1) {byte b_2[] = new byte[2];b_2[0] = base[firstByte(b[len - 1])];b_2[1] = base[lastOneByte(b[len - 1], 6)];sb.append(new String(b_2));return sb.append("==").toString();} else if (more_len == 2) {byte b_3[] = new byte[3];b_3[0] = base[firstByte(b[len - 2])];b_3[1] = base[secondByte(b[len - 2], b[len - 1])];b_3[2] = base[lastOneByte(b[len - 1], 4)];sb.append(new String(b_3));return sb.append("=").toString();}return sb.toString();}以上整个编码函数的实现就完成了,对于解码的实现下面直接给出代码。
@Overridepublic byte baseIndex(byte b) {for (int i = 0; i < base.length; i++) {if (base[i] == b) {return (byte) i;}}return -1;}@Overridepublic byte backLastOne(byte last_b, byte next_b, int move_l, int move_b) {int r_l = last_b & 0xff;int r_n = next_b & 0xff;r_l = r_l << move_l;r_n = r_n << move_b;r_n = r_n >>> move_b;return (byte) ((r_l | r_n) & 0xff);}@Overridepublic byte backFirst(byte first, byte second) {int r_f = first & 0xff;int r_s = second & 0xff;r_f = r_f << 2;r_s = r_s >>> 4;return (byte) ((r_f | r_s) & 0xff);}@Overridepublic byte backSecond(byte second, byte third) {int r_s = second & 0xff;int r_t = third & 0xff;r_s = r_s << 4;r_t = r_t >>> 2;return (byte) ((r_s | r_t) & 0xff);}@Overridepublic byte backThird(byte third, byte fourth) {int r_t = third & 0xff;int r_f = fourth & 0xff;r_t = r_t << 6;return (byte) ((r_t | r_f) & 0xff);}@Overridepublic String backEncode(byte[] b) {StringBuffer sb = new StringBuffer();Vector<Byte> list = new Vector<Byte>();int real_len = b.length;int len = real_len - 2;int more_len = len & 3;int use_len = len - more_len;for (int i = 0; i < use_len; i += 4) {list.add(backFirst(baseIndex(b[i]), baseIndex(b[i + 1])));list.add(backSecond(baseIndex(b[i + 1]), baseIndex(b[i + 2])));list.add(backThird(baseIndex(b[i + 2]), baseIndex(b[i + 3])));}Enumeration e = list.elements();byte bytes[] = new byte[list.size()];int k = -1;while (e.hasMoreElements()) {bytes[++k] = (Byte) e.nextElement();}sb.append(new String(bytes));if (more_len == 2) {byte b_1[] = new byte[1];b_1[0] = backLastOne(baseIndex(b[len - 2]), baseIndex(b[len - 1]),2, 6);sb.append(new String(b_1));}if (more_len == 3) {byte b_2[] = new byte[2];b_2[0] = backFirst(baseIndex(b[len - 3]), baseIndex(b[len - 2]));b_2[1] = backLastOne(baseIndex(b[len - 2]), baseIndex(b[len - 1]),4, 4);sb.append(new String(b_2));}return sb.toString();}
- 自定义Base64编码和解码的实现
- Base64编码解码和URLEnocde编码解码的C实现
- JavaScript实现的Base64编码和解码
- JavaScript实现的Base64编码和解码
- JavaScript实现的Base64编码和解码
- JavaScript实现的Base64编码和解码
- Base64编码、解码的实现
- Base64编码、解码的实现
- Base64编码、解码的实现
- Base64编码、解码的实现
- C#实现Base64编码与解码 自定义
- base64的编码和解码
- Base64的编码和解码
- BASE64 的编码和解码
- 利用 XML 实现 BASE64 编码和解码
- java实现base64编码和解码
- base64编码和解码
- BASE64编码和解码
- IT外包 OpenEIM 强调CMMI等级
- 《自己动手写一个操作系统》个人实践1
- SGU 180 Inversions
- 10.app后端选择什么开发语言
- KMP算法与一个经典概率问题
- 自定义Base64编码和解码的实现
- FZU 1004 || HOJ 1058 Number Triangles
- Spring框架的初步简单介绍
- 13.4.2 用计量单位格式化数据
- Directx中的拾取方法
- Windows 2008 R2 终端服务器授权安装配置
- C语言面试题
- poj2886Who Gets the Most Candies?
- 一款后台管理界面的好用框架