Base64编解码

合集下载
相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Base64编解码
一、编码原理
Base64是一种基于64个可打印字符来表示二进制数据的表示方法。

由于2的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。

三个字节有24个比特,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。

编码后的数据比原来的数据略长,是原来的4/3倍。

它可用来作为电子邮件的传输编码。

在Base64中的可打印字符包括字母A-Z、a-z、数字0-9 ,这样共有62个字符,此外两个可打印符号在不同的系统中而不同(Base64de 编码表如下所示)。

Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据。

包括MIME的email,email via MIME, 在XML中存储复杂数据.
Base64编码表
二、编码流程
步骤1:将要编码的所有字符都转化成对应的ASCII码。

步骤2:将所有的ASCII码转换成对应的8位长的二进制数。

步骤3:将所得的二进制数从高位到低位开始分成6位一组,最后一组不足六的则补充0
步骤4:将每组二进制数转换成十进制数,然后对照base64的编码表查找得到相应的编码。

注意:1、要求被编码字符是8bit的,所以须在ASCII编码范围内,\u0000-\u00ff,中文就不行。

2、如果被编码的字符串中字符的个数为3的倍数,按照上面的步骤即可得到正确的base64编码。

但是如果不是3的倍数则要分情况讨论。

如果是3的倍数余1,则要在编好的码字后面加上两个“=”,如果是3的倍数余2,这要在编好的码字后面加上一个“=”。

(例如w的base64编码为dw==,w1的base64编码为dzE=)
下面我们来对具体的字符串进行编码举例,以便更好的理解编码流程:
编码「Man」
在此例中,Base64算法将三个字符编码为4个字符
特殊情况
A的编码为QQ= =
BC的编码为QkM=
三、核心算法程序
算法的基本原理如下:由于每次转换都需要6个bit,而这6个bit可能都来自一个字节,也可以来自前后相临的两个字节。

定义两个变量:prevByteBitCount和nextByteBitCount,这两个变量分别表述从前一个和后一个节字取得的bit数。

如果prevByteBitCount为0,表示6个bit全部来自下一个字节的高6位。

如果nextByteBitCount = 0,表示6个bit全部来自前一个字节的低6位。

最后通过适当的移位获得所需要的6个bit,再在上面的base64编码表中查找相应的字符。

算法的实现代码如下:
public static String encoder(byte[] bytes)
{
StringBuilder result = new StringBuilder();
String base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; // prevByteBitCount表示从前一个字节取得的bit数,nextByteBitCount表示从后一个字节取得的bit数
int prevByteBitCount = 0, nextByteBitCount = 6;
// i表示当前的数组索引,n表示已经处理的位数
int i = 0, n = 0;
// byteCount表示总的位数
int byteCount = 8 * bytes.length;
byte b = 0;
while (true)
{
// 处理从前后两个字节取得位数的情况
if (prevByteBitCount > 0 && nextByteBitCount > 0)
{
// 将前一个字节的低位向左移nextByteBitCount个bit,并使下一个字节的高位(nextByteBitCount指定的位数)右移到字节的最低位,
// 然后将两个位移结果进行逻辑或,也就是将从前一个字节和后一个字节取得的相应的bit合并为一个字节的低位
b = (byte) (((0xff & bytes[i]) << nextByteBitCount) | ((0xff & bytes[i + 1]) >> (8 - nextByteBitCount)));
// 将逻辑或后的结果的最高两个bit置成0
b = (byte) (b & 0x3f);
prevByteBitCount = 8 - nextByteBitCount;
nextByteBitCount = 6 - prevByteBitCount;
}
// 处理从后一个字节取得高6位的情况
else if (prevByteBitCount == 0)
{
// 后一个字节的高6位右移动低6位
b = (byte) ((0xff & bytes[i]) >> (8 - nextByteBitCount));
// 处理后面的位时,就是从前一个字节取2个bit,从后一个字字取4个bit prevByteBitCount = 2;
nextByteBitCount = 4;
}
// 处理从前一个字节取得低6位的情况
else if (nextByteBitCount == 0)
{
// 将前一个字节的最高两个bit置成0
b = (byte) (0x3f & bytes[i]);
// 处理后面的位时,从后一个字节取6个bit
prevByteBitCount = 0;
nextByteBitCount = 6;
}
result.append(base64.charAt(b));
n += 6;
i = n / 8;
int remainBitCount = byteCount - n;
if (remainBitCount < 6)
{
// 将剩余的bit补0后,仍然需要在base64编码表中查找相应的字符,并添加到结果字符串的最后
if (remainBitCount > 0)
{
b = bytes[bytes.length - 1];
b = (byte) (0x3f & (b << (6 - remainBitCount)));
result.append(base64.charAt(b));
}
break;
}
}
// 如果总bit数除3的余数为1,加一个“=”,为2,加两个“=”
n = byteCount % 3;
for (i = 0; i < n; i++)
result.append("=");
return result.toString();
}
对于程序的理解:这个程序应该只是总程序的一部分,它主要实现了对二进
制代码分成以6位长为一组的分组,考虑了位数不足的情况,个人觉得这个是程序中的难点,所以就把它放进来了。

在这个程序中直接调用了查找base64编码表这个函数。

四、解码
Base64的解码原理很简单,其实就是编码的逆过程。

步骤1:将所给的字符在base64编码表中查到相应的数值
步骤2:将数值均转化成6位的二进制数
步骤3:将二进制数从高位到低位的顺序,以8为长度分组。

(若所给的base64码结尾没有“=”的情况,即字符数正好是4的倍数。

如果有“=”,这不是8的倍数,此时需要将最后的两位或者四位省去。

这就可能导致不同的符号可以解码出相同的编码,如下面所示的例子。


步骤4:将每组的二进制数转换成对应的ASCII代码。

这样就可以得到解码后的字符。

举例说明:
解码er==
Base64编码表中对应的值为30 43
每个化成对应6为二进制位011110 101011
以8位长为一组,多余省去,这可得01111010
则其ASCII码数值为7Ah,对应字符为Z
eq==解码所得结果也为Z。

注意:如果在步骤三中所得的数在ASCII码表中找不到对应数,则会出现解码
错误。

例如erYT解码得到就是Z!!(这是我在网上的base64解码器中实验得
到的结果)
五、感悟
我们觉得Base64的编码、解码原理很简单,但是它的应用范围挺广的,而且它的源代码对于我们来说也不简单(有的部分知道怎么回事,但是不知道怎么用程序来实现)。

在这次找编解码的过程中,我们受益良多。

一开始找的都是那些很大的音频、视频编解码,像ACC、OGG、H.264等等,基本上都看不懂,只能知道它是干什么的。

后来又找到了曼彻斯特编码、AMI编解码,结果有人已经做了,所以最后我们选了Base64编解码。

所以这次作业让我们了解了好多以前完全没有接触过的代码,收获颇丰。

相关文档
最新文档