Base64编码及编码性能测试
来源:互联网 发布:惠州网络问政被屏蔽 编辑:程序博客网 时间:2024/05/21 18:42
原创文章,欢迎转载。转载请注明出处:http://blog.csdn.net/jmppok/article/details/17096685
1.什么是Base64编码
Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6位为一个单元,对应某个可打印字符。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。
具体可参照维基百科:维基百科 Base64
2.为什么要使用Base64编码
在计算机使用过程中,经常会遇到Binary数据,即一个数据块,我们知道其首地址和长度,通过指针即可对其进行快速访问。
但实际环境中,我们又经常需要将这个数据转换为String字符串,而在String字符串中有一个规则,遇到'\0'字符便认为字符串结束。我们不能保证Binary数据中有没有'\0'字符,所以直接将Binary数据赋值给String便可能出现问题。
而解决这一问题的办法就是使用Base64编码,上面说到Base64编码只有64个字符,'A-Z' 'a-z' '0-9' + /。没有'\0'字符,我们只要先办Binary转为Base64编码格式,即可避免出现'\0'字符,从而在赋值给String时变得可靠。
3.编码规则
二机制数据通过8位表示一个字符,Base64通过6位表示一个字符。所以将一个二进制数据转换为Base64编码,其长度要增加 (lengh*8/6)倍。
其规则如下:
1)依次从Binary数据中取出6位,转换为一个Base64字符;
2)如果最后有剩余则以0补够6位。在补位的同时,需要在Base64结尾以‘=’进行标识,一个'='表示补2个0,两个'==',表示补4个0。
需要注意的是第二条规则,由于数据本身是8的倍数,所以每次取6位,最后的余数只能是2或4。这两个则通过在Base64结尾加‘=’和'=='标识。
下面是一个Base64编码索引表和补位的说明:
Base64索引表:
如果要编码的字节数不能被3整除,最后会多出1个或2个字节,那么可以使用下面的方法进行处理:先使用0字节值在末尾补足,使其能够被3整除,然后再进行base64的编码。在编码后的base64文本后加上一个或两个'='号,代表补足的字节数。也就是说,当最后剩余一个八位字节(一个byte)时,最后一个6位的base64字节块有四位是0值,最后附加上两个等号;如果最后剩余两个八位字节(2个byte)时,最后一个6位的base字节块有两位是0值,最后附加一个等号。 参考下表:
4.举例说明
1) 0 1 2编码为Base64
0 1 2 二进制表示为 0011 0000 0011 0001 0011 0010
转换为Base64为 001100 000011 000100 110010
即 12 3 4 50
从编码表中查找 M D E y
所以对应的Base64编码为 "MDEy"
2) 0123编码为Base64(需要补位)
0 1 2 3 二进制表示为 0011 0000 0011 0001 0011 0010 0011 0011
转换为Base64为 001100 000011 000100 110010 001100 110000(后面补4个0)
即 12 3 4 50 12 48
从编码表中查找 M D E y M w
所以对应的Base64编码为 "MDEyMw==" (由于补了4个0,因此需要加上'==')
5.C++代码
Base64.h
#ifndef BASE64_H_#define BASE64_H_void base64_encode(const char * pData, int len, char * pOut);void base64_decode(const char * pData, int len, char * pOut);int calc_base64_len(int data_len);int calc_data_len(const char * base64, int base64_len);#endif
Base64.cpp
#include "Base64.h"int calc_base64_len(int data_len){int last = data_len*8%6;if(last == 0){return data_len*8/6;}else{int base64_len = data_len*8/6+1;base64_len += (last==2?2:1);return base64_len;}}int calc_data_len(const char * base64, int base64_len){int dec = 0;while(base64[base64_len-1-dec]== '='){dec++;}return ((base64_len-dec)*6)/8;}char _getBase64Char(char c){if(c>=0 && c<26){return 'A'+c;}else if(c>=26 && c<52){return 'a'+c-26;}else if(c>=52 && c<62){return '0'+c-52;}else if(c==62){return '+';}else if(c==63){return '/';}}char _getCharOfBase64(char c){if(c>='A' && c<='Z'){return c-'A';}else if(c>='a' && c<='z'){return c-'a'+26;}else if(c>='0' && c<='9'){return c-'0'+52;}else if(c=='+'){return 62;}else if(c=='/'){return 63;}}void base64_encode(const char * pData, int len, char * pOut){int index = 0;while(len-index>=3){const char * p1 = pData+index;const char * p2 = p1+1;const char * p3 = p2+1;char c1 = ((*p1) & (0b11111100)) >>2;char c2 = ((*p1) & (0b00000011))<<4 | ((*p2) & 0b11110000)>>4;char c3 = ((*p2) & (0b00001111))<<2 | ((*p3) & 0b11000000)>>6;char c4 = (*p3) & (0b00111111);*(pOut++)=_getBase64Char(c1);*(pOut++)=_getBase64Char(c2);*(pOut++)=_getBase64Char(c3);*(pOut++)=_getBase64Char(c4);index+=3;}int last = len-index;if(last==1){const char * p1 = pData + index;char c1 = ((*p1) & (0b11111100)) >>2;char c2 = ((*p1) & (0b00000011))<<4;*(pOut++)=_getBase64Char(c1);*(pOut++)=_getBase64Char(c2);*(pOut++)='=';*(pOut++)='=';}else if(last == 2){const char * p1 = pData+index;const char * p2 = p1+1;char c1 = ((*p1) & (0b11111100)) >>2;char c2 = ((*p1) & (0b00000011))<<4 | ((*p2) & 0b11110000)>>4;char c3 = ((*p2) & (0b00001111))<<2 ;*(pOut++)=_getBase64Char(c1);*(pOut++)=_getBase64Char(c2);*(pOut++)=_getBase64Char(c3);*(pOut++)='=';//*(pOut++)='=';}}void base64_decode(const char * pData, int len, char * pOut){int dec = 0;while(pData[len-1-dec]== '='){dec++;}int real_len = len-dec;int index=0;while(real_len-index>=4){const char * p1 = pData+index;const char * p2 = p1+1;const char * p3 = p2+1;const char * p4 = p3+1;char c1 = _getCharOfBase64(*p1);char c2 = _getCharOfBase64(*p2);char c3 = _getCharOfBase64(*p3);char c4 = _getCharOfBase64(*p4);*(pOut++)=(c1)<<2 | ((c2)&(0b00110000))>>4;*(pOut++)=((c2)&(0b00001111))<<4 | ((c3)&(0b00111100))>>2;*(pOut++)=((c3)&(0b00000011))<<6 | (c4)&(0b00111111);index+=4;}int last = real_len-index;if(last == 2){const char * p1 = pData+index;const char * p2 = p1+1;char c1 = _getCharOfBase64(*p1);char c2 = _getCharOfBase64(*p2);*(pOut++)=(c1)<<2 | ((c2)&(0b00110000))>>4;}else if(last ==3){const char * p1 = pData+index;const char * p2 = p1+1;const char * p3 = p2+1;char c1 = _getCharOfBase64(*p1);char c2 = _getCharOfBase64(*p2);char c3 = _getCharOfBase64(*p3);*(pOut++)=(c1)<<2 | ((c2)&(0b00110000))>>4;*(pOut++)=((c2)&(0b00001111))<<4 | ((c3)&(0b00110000))>>2;}}
main.cpp
#include <stdio.h>#include "time.h"#include "Base64.h"const char * file_in = "c:\\temp\\1.jpg";const char * file_mid = "c:\\temp\\1.base64";const char * file_out="c:\\temp\\11.jpg";int main(int argc, char **argv){char * pData;int len;FILE * fp = fopen(file_in,"rb");if(fp){fseek(fp,0,SEEK_END);len = ftell(fp);fseek(fp,0,SEEK_SET);pData = new char[len];fread(pData,1,len,fp);fclose(fp);}int base64_len = calc_base64_len(len);//int base64_len = len*8/6+1;//base64_len += (len*8%6)/2; //'='char * pOut = new char[base64_len];//encodeBase64(pData,len,pOut);base64_encode(pData,len,pOut);/*clock_t begin,end;begin = clock();int loop=0;while(loop<1000){base64_encode(pData,len,pOut);loop++;}end = clock();printf("time used %d ms.\n",(end-begin));return 0;*/ //pOut[base64_len-1]='\0';fp = fopen(file_mid,"wb");if(fp){fwrite(pOut,1,base64_len, fp);fclose(fp);}if(pData){delete []pData;}if(pOut){delete []pOut;}// readfp = fopen(file_mid,"rb");if(fp){fseek(fp,0,SEEK_END);base64_len = ftell(fp);fseek(fp,0,SEEK_SET);pData = new char[base64_len];fread(pData,1,base64_len,fp);fclose(fp);}//int dec = 0;//while(pData[base64_len-1-dec]== '=')//{//dec++;//}//len = ((base64_len-dec)*6)/8;len = calc_data_len(pData,base64_len);pOut = new char[len];//decodeBase64(pData,base64_len,pOut);base64_decode(pData,base64_len,pOut);fp = fopen(file_out,"wb");if(fp){fwrite(pOut,1,len,fp);fclose(fp);}if(pData){delete []pData;}if(pOut){delete []pOut;}return 0;}
main.cpp读取c:\temp\1.jpg,进行Base64编码,将编码结果写入c:\temp\1.base64, 然后再从c:\temp\1.base64中读取,解码还原,写入 c:\temp\11.jpg.
6.Base64编码性能测试
测试环境:普通PC机 i5 3470 3.2GGhz,内存4G,可用3.76 ,win7 32位
使用上述代码,编译环境为mingw。
只测试了Base64 encode的性能,encode1000次,取平均时间:
100K大小数据 1.014ms
200K大小数据 1.981ms
300K 2.917ms
500K 4.961ms
1M 10.624ms
总结:Base64编码耗时与数据大小成线形比例,在数据量不大时耗时很小。
7.总结与改进
1)该测试程序为本人随手而写,还有许多改进空间;以此程序进行测试的结果,仅作参考。
2)由于时间有限,未进行Base64解码的测试。
在这篇文章中进行了改进,encode效率提高8倍左右。
http://blog.csdn.net/jmppok/article/details/17137839
- Base64编码及编码性能测试
- Base64编码及编码性能测试 [改进]
- Base64编码及解码
- Base64编码及代码
- Base64编码及解码
- Base64编码原理及编码、解码实现
- Java Base64编码及解码
- Base64编码及期作用
- MD5加密算法及BASE64编码
- MD5加密及BASE64编码
- Base64编码图片及MIME
- Base64编码
- Base64编码
- base64编码
- BASE64编码
- Base64编码
- BASE64编码
- base64 编码
- 打印机条码问题
- AngularJS中locationchange、routechange事件
- Oracle EBS值集
- Activity的启动模式与flag详解
- document.forms[0].submit() 拒绝访问 js
- Base64编码及编码性能测试
- 加速你的Hibernate引擎(下)
- HTTP Content-type头信息及文件类型对照
- COM组件 #import ; tlb, tlh, tli 文件
- 取得程序运行目录
- 经典算法
- Android中的Toast重复显示的问题
- 压缩索引
- 如何将WebRoot部署到tomcat中