BASE64 编码实现

用了几天的时间实现了BASE64编码,编程能力还有待提高啊 :arrow: 。

下面就描述下我的实现过程吧。

首先,当然要知道BASE64的编码规则了,至于有什么用这里就不再描述啦。编码规则查看这篇文章[url=http://blog.csdn.net/SCHOLAR_II/archive/2009/02/11/3877606.aspx]《BASE64编码规则》[/url],也是在网上搜索到的。大致可分为以下两步:一、字节转换(3*8 -> 4*6);二、字符编码。


一、字节转换(3*8 -> 4*6)

先计算出转码后数组的长度,用来创建新数组及保存转码后的内容。
int desLength = (int) ((src.length + 2) / 3) * 4;

把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式。

进行如下操作:



des[i * 4] = (byte) (src[i * 3] >>> 2);
des[i * 4] &= 0x3f; // 最高两位置0
des[i * 4 + 1] = (byte) (src[i * 3] << 4 | ((src[i * 3 + 1] >>> 4) & 0x0f));
des[i * 4 + 1] &= 0x3f; // 最高两位置0
des[i * 4 + 2] = (byte) (src[i * 3 + 1] << 2 | ((src[i * 3 + 2] >>> 6) & 0x03));
des[i * 4 + 2] &= 0x3f; // 最高两位置0
des[i * 4 + 3] = (byte) (src[i * 3 + 2] & 0x3f);


第二行的目的是将转码后的最高两位置0,第三行最后的 & 0x0f 操作是确保移位后高四位为0。进行这步操作是因为 Java 中的位运算是对32位的整形进行的,对于byte类型会自动转码成int类型后再进行位运算。此时有符号运算(">>")和无符号运算(">>>")效果是一样的,故一定要进行位运算以保证高位为0。

上述操作只对代码量是3的整数倍时有效。当代码量不是3的整数倍时,代码量/3的余数自然就是2或者1。此时,转换结果不够6位的用0来补上相应的位置,之后再在6位的前面补两个0。转换完空出的结果就用就用“=”来补位。

这一步要判断代码的长度,并进行相对应的不同的处理。想了半天,还是用了个小技巧,用Java的异常帮忙获得最后要进行处理的代码。

try {
// 可以被完全转换的代码,代码量是3的整数倍
} catch (ArrayIndexOutOfBoundsException e) {
// 特殊处理的代码,及需判断用“=”补位的代码
if ((src.length % 3) == 2) { // 存在中间项
des[des.length - 3] = (byte) (src[src.length - 2] << 4 | src[src.length - 1] >>> 4);
des[des.length - 3] &= 0x3f;
des[des.length - 2] = (byte) (src[src.length - 1] << 2 | 0x00);
des[des.length - 2] &= 0x3f;
des[des.length - 1] = 0x40;
} else {
des[des.length - 3] = (byte) (src[src.length - 1] << 4 | 0x00);
des[des.length - 3] &= 0x3f;
des[des.length - 2] = 0x40;
des[des.length - 1] = 0x40;
}
}

这样,字节转换就完成啦。


二、字符编码


char c[] = new char[des.length];
for (int i = 0; i < des.length; i++) {
if (des[i] >= 0 && des[i] <= 25)
c[i] = (char) (des[i] + 'A');
else if (des[i] >= 26 && des[i] <= 51)
c[i] = (char) (des[i] - 26 + 'a');
else if (des[i] >= 52 && des[i] <= 61)
c[i] = (char) (des[i] -52 + '0');
else if (des[i] == 62)
c[i] = '+';
else if (des[i] == 63)
c[i] = '/';
else
c[i] = '=';
}



解码和编码是一样的步骤,就不再详述啦。

BASE64编码在Java 标准API库中好像没有提供,但sun在JDK中提供了两个类来处理。路径如下:
sun.misc.BASE64Encoder和sun.misc.BASE64Dncoder
用法在下面的代码中用展示。

下面是完整的代码:


import java.io.IOException;


public class Base64 {

private static byte src[];
private static byte des[];

public static char[] encoding(String str) {
src = str.getBytes();
int desLength = (int) ((src.length + 2) / 3) * 4; // 计算目标数组的长度
des = new byte[desLength];
// 3*8 转 4*6
try {
for (int i = 0; i * 4 < des.length; i++) {
des[i * 4] = (byte) (src[i * 3] >>> 2);
des[i * 4] &= 0x3f;
des[i * 4 + 1] = (byte) (src[i * 3] << 4 | ((src[i * 3 + 1] >>> 4) & 0x0f));
des[i * 4 + 1] &= 0x3f;
des[i * 4 + 2] = (byte) (src[i * 3 + 1] << 2 | ((src[i * 3 + 2] >>> 6) & 0x03));
des[i * 4 + 2] &= 0x3f;
des[i * 4 + 3] = (byte) (src[i * 3 + 2] & 0x3f);
}
} catch (ArrayIndexOutOfBoundsException e) {
if ((src.length % 3) == 2) { // 存在中间项
des[des.length - 3] = (byte) (src[src.length - 2] << 4 | ((src[src.length - 1] >>> 4) & 0x0f));
des[des.length - 3] &= 0x3f;
des[des.length - 2] = (byte) (src[src.length - 1] << 2 | 0x00);
des[des.length - 2] &= 0x3f;
des[des.length - 1] = 0x40;
} else {
des[des.length - 3] = (byte) (src[src.length - 1] << 4 | 0x00);
des[des.length - 3] &= 0x3f;
des[des.length - 2] = 0x40;
des[des.length - 1] = 0x40;
}
}

// 编码 byte[] -> char[]
char c[] = new char[des.length];
for (int i = 0; i < des.length; i++) {
if (des[i] >= 0 && des[i] <= 25)
c[i] = (char) (des[i] + 'A');
else if (des[i] >= 26 && des[i] <= 51)
c[i] = (char) (des[i] - 26 + 'a');
else if (des[i] >= 52 && des[i] <= 61)
c[i] = (char) (des[i] -52 + '0');
else if (des[i] == 62)
c[i] = '+';
else if (des[i] == 63)
c[i] = '/';
else
c[i] = '=';
}
return c;
}

public static byte[] decoder(String str) {
// 解码 char[] -> byte[]
char c[] = str.toCharArray();
byte[] b = new byte[c.length];
for (int i = 0; i < c.length; i++) {
if (c[i] >= 'A' && c[i] <= 'Z')
b[i] = (byte) (c[i] - 'A');
else if (c[i] >= 'a' && c[i] <='z')
b[i] = (byte) (c[i] - 'a' + 26);
else if (c[i] >= '0' && c[i] <= '9')
b[i] = (byte) (c[i] - '0' + 52);
else if (c[i] == '+')
b[i] = 0x3e;
else if (c[i] == '/')
b[i] = 0x3f;
else
b[i] = 0x40;
}

// 4*6 -> 3*8
int num = 0; // 记录"="的个数
if (b[b.length - 1] == 0x40) {
num++;
if (b[b.length - 2] == 0x40)
num++;
}
int aLength = b.length / 4 * 3 - num;
byte [] a = new byte[aLength];
try {
for (int i = 0; i * 3 < a.length; i++) {
a[i * 3] = (byte) ((b[i * 4] << 2) | ((b[i * 4 + 1] >> 4) & 0x03));
a[i * 3 + 1] = (byte) ((b[i * 4 + 1] << 4) | ((b[i * 4 + 2] >> 2) & 0x0f));
a[i * 3 + 2] = (byte) ((b[i * 4 + 2] << 6) | (b[i * 4 + 3] & 0x3f));
}
} catch (ArrayIndexOutOfBoundsException e) {
// do nothing
}
return a;
}

// Test
public static void main(String[] args) throws IOException {
String str = new String("Hello,我是翔之骓。英文名是 Cream!");
char[] temp = Base64.encoding(str);
System.out.println(temp);
System.out.println(new String(Base64.decoder(new String(temp))));

// use sun BASE64 encoding
sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
System.out.println("系统提供:\n" + encoder.encode(src));
sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
System.out.println(new String(decoder.decodeBuffer(encoder.encode(src))));
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值