技术经验分享:base64详解

简介: 技术经验分享:base64详解

base64详解


前置知识


位与字节


二进制系统中,每个0或1就是一个位(bit,比特),也叫存储单元,位是数据存储的最小单位。


其中8bit就称为一个字节(Byte)。


1B=8位


位运算


与运算:符号表示为&。运算规则:两位同时为“1”,结果才为“1”,否则为0或运算:符号表示为|。运算规则:两位只要有一位为“1”,结果就为“1”,否则为0


典型:


0000 0101 : 代表高四位, 代表低四位


char1&0x3:0x3是十六进制数,用二进制表示是0000 0011,用于提取char1的低两位,就是有1的那两位


char2&0xf0:0xf0是一个十六进制数,表示为二进制 11110000,用于提取 char2 的高四位。


移位操作


右移,[左移


// 左移


01101000 [ 2 -> 101000(左侧移出位被丢弃) -> 10100000(右侧空位一律补0)


// 右移


01101000 ] 2 -> 011010(右侧移出位被丢弃) -> 00011010(左侧空位一律补0)


base64编码


base64编码的概念


base64编码就是将字符串以每3个比特(bit)的字节子序列拆分为4个6比特(bit)的字节子序列(这个6比特是有效字节,最左边两个永远为0,其实也算是8比特的字节),再将得到的子序列查找base64的编码索引表,得到对应的字符拼接成新的字符串的一种编码方式。


每3个8比特(bit)的字节子序列拆分成4个6比特(bit)的字节序列的拆分过程如下图所示:


为什么base64编码后的大小是原来的4/3倍


因为6和8的最小公倍数是24,所以3个8比特的字节刚好可以拆分成4个6比特的字节,3 8 = 6 4。计算机中,因为一个字节需要8个存储单元存储,所以我们要把6个比特往前面补两位0,补足8个比特。如下图所示:


很明显,补足后所需的存储单元为32个,是原来所需的24个的4/3倍。现在大家明白为什么base64编码后的大小是原来的4/3倍了吧。


为什么命名为base64呢


因为6位的二进制有2的6次方个,也就是二进制数(0000 0000 - 0011 1111)之间的代表0-63的64个二进制数。


不是说一个字节是用8位二进制表示的吗,为什么不是2的8次方?


因为我们得到的8位二进制数的前两位永远是0,真正的有效位只有6位,所以我们所能够得到的二进制数只有2的6次方个。


base64字符是哪64个


Base64的编码索引表,字符选用了"A-Z、a-z、0-9、+、/" 64个可打印字符来代表(00000000-00111111)这64个二进制数。即


let base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'


编码原理


我们不妨自己先思考一下,要把3个字节拆分成4个字节可以怎么做?你的实现思路和我的实现思路有哪个不同,我们之间又会碰出怎样的火花?


流程图


思路


分析映射关系:a b c -> x y z i


从高位到地位添加索引分析这个过程:


x:(前面补2个0)a的前6位 => 00a【7】a【6】 a【5】a【4】a【3】a【2】


y:(前面补2个0)a的后2位 + b的前4位 => 00a【1】a【0】 b【7】b【6】b【5】b【4】


z:(前面补2个0)b的后4位 + c的前2位 => 00b【3】b【2】 b【1】b【0】c【7】c【6】


i:(前面补2个0)c的后6位 => 00c【5】c【4】 c【3】c【2】c【1】c【0】


通过上面的分析,很容易得到实现思路:


将字符对应的ASCII编码转为8位的二进制


将每三个8位二进制数进行以下操作:


(1)将第一个数右移2位,得到第一个6位有效位二进制数


(2)将第一个数&0x3之后左移4位,得到第二个6位有效位二进制数的第一个和第二个有效位,将第二个数 & 0xf0之后右移位4位,得到第二个6位有效位二进制数的后四位有效位,两者取且得到第二个6位有 效位二进制


(3)将第二个数 & 0xf之后左移位2位,得到第三个6位有效位二进制数的前四位有效位,将第三个数 & 0xC0之后右移位6位,得到第三个6位有效位二进制数的后两位有效位,两者取且得到第三个6位有效 位二进制


(4)将第三个数 & 0x3f,得到第四个6位有效位二进制数


将获得的6位有效位二进制数转十进制,查找对应base64字符


注释:


char1&0x3的计算方法:先将char1和0x3转换为二进制,即0000 0011,按位与,作用是取char1的低两位


& 0xf0,即1111 0000,取高四位


& 0xf ,即0000 1111,取低四位


& 0xC0,即1100 0000,取高两位


& 0x3f ,即0011 1111,取低六位


base64编码实例


0x01


我们以hao字符串为例,观察base64编码的过程,我们将上面转换通过代码逻辑分析实现吧。


编码结果为aGFv


#include


char base64EncodeChars【】 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";


int main() {


char str【】="hao";


char char1,char2,char3,out1,out2,out3,out4;


char out【5】;


// 将字符对应的ASCII值转为8位二进制数,& 0xff是为了保留8位二进制


char1 = str【0】 & 0xff; // h 的ASCII为 104 二进制为 01101000


char2 = str【1】 & 0xff; // a 的ASCII为 97 二进制为 01100001


char3 = str【2】 & 0xff; // o 的ASCII为 111 二进制为 01101111


// 输出6位有效字节二进制数


out1 = char1 ] 2; // 26 011010


out2 = (char1 & 0x3) [ 4 | (char2 & 0xf0) ] 4; // 6 000110


out3 = (char2 & 0xf) [ 2 | (char3 & 0xc0) ] 6; // 5 000101


out4 = char3 & 0x3f; // 47 101111


out【0】 = base64EncodeChars【out1】; //输出out1对应的ASCII


out【1】 = base64EncodeChars【out2】; //输出out2对应的ASCII


out【2】 = base64EncodeChars【out3】; //输出out3对应的ASCII


out【3】 = base64EncodeChars【out4】; //输出out4对应的ASCII


out【4】 = '\0'; //去掉输出末尾的'hao'


printf("%s",out);


return 0;


}


0x02


扩展至多字符字符串


#include


#include[span style="color: rgba(0, 0, 255, 1)">string.h>


char base64EncodeChars【】="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;


int main(){


char str【】="haohaohao";


char char1,char2,char3,out1,out2,out3,out4;


char out【100】;


int len = strlen(str);


int index = 0;


int outindex = 0;


while(index [span style="color: rgba(0, 0, 0, 1)"> len){


char1 = str【index++】 & 0xff ;


char2 = str【index++】 & 0xff ;


char3 = str【index++】 & 0xff ;


out1 = char1 ] 2 ;


out2 = (char1 & 0x3) [ 4 | (char2 & 0xf0) ] 4 ;


out3 = (char2 & 0xf) [ 2 | (char3 & 0xc0) ] 6 ;


out4 = char3 & 0x3f ;


out【outindex++】 = base64EncodeChars【out1】;


out【outindex++】 = base64EncodeChars【out2】;


out【outindex++】 = base64EncodeChars【out3】;


out【outindex++】 = base64EncodeChars【out4】;


}


out【outindex】 = '\0';


printf("%s\n",out);


return 0;


}


0x03


究极版base64编码


#include


#include


char base64Encode(const char str) {


// Base64 characters


const char base64EncodeChars【】 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";


// Get string length


int len = 0;


while (str【len】 != '\0') {


len++;


}


// Output string


char out = (char)malloc(len 4 / 3 + 4);


char v11 = out;


int index = 0;


while (index [span style="color: rgba(0, 0, 0, 1)"> len) {


// Define input and output bytes


unsigned char char1, char2, char3;


unsigned char out1, out2, out3, out4;


// Convert characters to ASCII codes


char1 = str【index++】 & 0xff;


out1 = char1 ] 2;


if (index == len) {


out2 = (char1 & 0x3) [ 4;


sprintf(v11, "%c%c==", base64EncodeChars【out1】, base64EncodeChars【out2】);


break;


}


char2 = str【index++】 & 0xff;


out2 = ((char1 & 0x3) [ 4) | ((char2 & 0xf0) ] 4);


if (index == len) {


out3 = (char2 & 0xf) [ 2;


sprintf(v11, "%c%c%c=", base64EncodeChars【out1】, base64EncodeChars【out2】, base64EncodeChars【out3】);


break;


}


char3 = str【index++】 & 0xff;


out3 = ((char2 & 0xf) [ 2) | ((char3 //代码效果参考:http://www.jhylw.com.cn/423938089.html

& 0xc0) ] 6);

out4 = char3 & 0x3f;


sprintf(v11, "%c%c%c%c", base64EncodeChars【out1】, base64EncodeChars【out2】, base64EncodeChars【out3】, base64EncodeChars【out4】);


v11 += 4;


}


return out;


}


int main() {


char encodedStr = base64Encode("haohao");


printf("%s\n", encodedStr);


free(encodedStr);


encodedStr = base64Encode("haoha");


printf("%s\n", encodedStr);


free(encodedStr);


encodedStr = base64Encode("haoh");


printf("%s\n", encodedStr);


free(encodedStr);


return 0;


}


base64自定义字符编码


#include


#include


char base64Encode(const char str) {


// Base64 characters


const char base64EncodeChars【】 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";


// Get string length


int len = 0;


while (str【len】 != '\0') {


len++;


}


// Output string


char out = (char)malloc(len 4 / 3 + 4);


char* v11 = out;


int index = 0;


while (index [span style="color: rgba(0, 0, 0, 1)"> len) {


// Define input and output bytes


unsigned char char1, char2, char3;


unsigned char out1, out2, out3, out4;


// Convert characters to ASCII codes


char1 = str【index++】 & 0xff;


out1 = char1 ] 2;


if (index == len) {


out2 = (char1 & 0x3) [ 4;


sprintf(v11, "%c%c==", base64EncodeChars【out1】, base64EncodeChars【out2】);


break;


}


char2 = str【index++】 & 0xff;


out2 = ((char1 & 0x3) [ 4) | ((char2 & 0xf0) ] 4);


if (index == len) {


out3 = (char2 & 0xf) [ 2;


sprintf(v11, "%c%c%c=", base64EncodeChars【out1】, base64EncodeChars【out2】, base64EncodeChars【out3】);


break;


}


char3 = str【index++】 & 0xff;


out3 = ((char2 & 0xf) [ 2) | ((char3 & 0xc0) ] 6);


out4 = char3 & 0x3f;


sprintf(v11, "%c%c%c%c", base64EncodeC

相关文章
|
20天前
|
机器学习/深度学习 存储 人工智能
人工智能平台PAI产品使用合集之filePath该如何写
阿里云人工智能平台PAI是一个功能强大、易于使用的AI开发平台,旨在降低AI开发门槛,加速创新,助力企业和开发者高效构建、部署和管理人工智能应用。其中包含了一系列相互协同的产品与服务,共同构成一个完整的人工智能开发与应用生态系统。以下是对PAI产品使用合集的概述,涵盖数据处理、模型开发、训练加速、模型部署及管理等多个环节。
|
4天前
|
人工智能
技术经验分享:CF223C
技术经验分享:CF223C
|
4天前
|
C++ 开发者
技术经验分享:dumpbin的使用方法_dumpbin的基础使用
技术经验分享:dumpbin的使用方法_dumpbin的基础使用
|
2月前
|
移动开发 网络协议 Java
即时通讯技术文集(第38期):IM代码入门实践(Part2) [共15篇]
为了更好地分类阅读 52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第38 期。
48 1
|
2月前
|
安全 Java 数据库
即时通讯技术文集(第37期):IM代码入门实践(Part1) [共16篇]
为了更好地分类阅读 52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第37 期。
39 2
|
2月前
|
人工智能 前端开发 Devops
【专栏】洞察.NET 技术在现代开发中的作用
【4月更文挑战第29天】本文探讨了.NET技术在现代软件开发中的核心价值、应用及挑战。.NET提供语言统一性与多样性,强大的Visual Studio工具,丰富的类库,跨平台能力及活跃的开发者社区。实际应用包括企业级应用、Web、移动、云服务和游戏开发。未来面临性能优化、容器化、AI集成等挑战,需持续创新。开发者应深入理解.NET,把握技术趋势,参与社区,共创美好未来。
|
7月前
|
存储 前端开发 算法
了不起的Base64
了不起的Base64
《圆桌讨论: 从趋势、工具或相关的技术点谈APP的优化》电子版地址
圆桌讨论: 从趋势、工具或相关的技术点谈APP的优化
51 0
《圆桌讨论: 从趋势、工具或相关的技术点谈APP的优化》电子版地址
|
SQL 缓存 Java
JPA学习之路(基础篇)
📒 程序员小王的博客:(https://www.wolai.com/wnaghengjie/ahNwvAUPG2Hb1Sy7Z8waaF) 🎉 欢迎点赞 👍 收藏 ⭐留言 📝 😊 如有编辑错误联系作者,如果有比较好的文章欢迎分享给我,我会取其精华去其糟粕 ———————————————— 版权声明:本文为CSDN博主「程序员小王java」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_44385486/article/details/123046499
136 0
JPA学习之路(基础篇)
GitHub上这份阿里的Java高并发核心手册,即使再过20年依然“NB”
什么是高并发? 高并发(High Concurrency)通常是指通过设计保证系统能够同时并行处理很多请求。 通俗来讲,高并发是指在同一个时间点,有很多用户同时访问同一 API 接口或者 Url 地址。它经常会发生在有大活跃用户量,用户高聚集的业务场景中。 今天给大家分享一份由一位阿里大牛亲自操刀写出来的一份:Java高并发核心编程手册,号称即使再过20年这份资料依然不会被淘汰!