关于Base64编码
作者:唐风
Base 64是一种比较古老的编码方式,在通信中非常常见。它实现很简单。
What?
“Base64是一种基于64个可打印字符来表示二进制数据的表示方法(来自维基)”。这句话我一开始没有看懂,现在我用我懂的方式再解释一下:我们可以把通信的数据流分为两种,“二进制流”和“文本流”。(注意,后面的定义并不严谨)。文本流是指数据串是以“人类可读的字符”组成的,数据流中出现的 0x00,0x0a,0x0d 等数据一般都是特殊的控制数据(文本结束,或是换行、或者是其它的),而不是数据本身。二进制流是任意的一串数据(每个字节可以是从 0x00 到 0xff 的值,而不限于字符)。Base64 编码就是用可打印字符(A-Z,a-z,0-9,+/这64个“字符”)组成的“文本流”来表示任意的二进制流数据的一种编码方法。也就是:任意的二进制流,通过base64编码后会变成一串只由可见字符(A-Z,a-z,0-9,+/这64个“字符”)组成的文本数据流。
完整的base64定义可见参考RFC 1421和RFC 2045。
Why?
Base64有什么用?!base 64编码后的数据流会比原数据流更长(是原数据流长度的4/3,原因见How的部分),那为什么还要用这种方式进行编码呢?(一开始我很不理解的地方)
原因是:通信设备的种类繁多,设计各异,比如有些设备只能处理/传输7bit的数据,有些设备的通信模块只能处理文本流,等等,为了保证在这些设备之间仍然能无障碍地进行任何二进制数据(8bit为单位)的通信,就把这些数据重新编码成只由可打印字符组成的文本流。base64中选取的可打印字符几乎在任何设备上都支持(字符集采用US-ASCII标准)。另外还常会见到的一个场景是,要求数据从控制台(或者其它输入/输出设备)输入或是输出,由于这些输入输出设备只支持文本操作或显示,所以也需要把二进制数据流在可打印字符集之间进行转换(编解码)。
How?
Base64编码其实很简单。将二进制数据流每三个字符一组进行分组(24bit),分组后,将24bit分成4个6bit数据,为每6bit数据前加上2个bit的0,就会得到4个8bit数据(变成了4byte),每个byte的值都在0-63的范围之间。然后按预先设定的转换表,把这些值转换成对应的可打印字符。
前文本中引用的维基百科内容说明得也比较清楚。
过程参考下图:

这里有一个小细节需要注意,那就是如果要编码的数据串长度不是 3 的整数倍的情况下,需要在数据串后面补充若干(假设是N)个0x00使得数据长度恰好为 3 的整数倍。然后再进行处理。得到相应的base64字符流数据后,再把串最后面的N个A换成=号。
Base64的解码过程只需要反过来就可以了。
下面是C++的代码实现
static char const convert_table[] = "ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
vector<char> output;
output.reserve((_bin.size() * 4) / 3);
auto con_3bytes_to_4bytes = [&](uint8_t const * _3bytes_bin_data) {
output.push_back(convert_table[_3bytes_bin_data[0] >> 2]);
output.push_back(convert_table[((_3bytes_bin_data[0] & 0x03) << 4) | ((_3bytes_bin_data[1] >> 4) & 0x0f)]);
output.push_back(convert_table[((_3bytes_bin_data[1] << 2) & 0x3c) | (_3bytes_bin_data[2] >> 6)]);
output.push_back(convert_table[_3bytes_bin_data[2] & 0x3f]);
};
auto i = 0u;
for (; (i + 3) <= _bin.size(); i += 3) {
con_3bytes_to_4bytes(&_bin[i]);
}
if (i != _bin.size()) {
uint8_t left_data[3] = { 0 };
std::copy(begin(_bin) + i, end(_bin), left_data);
con_3bytes_to_4bytes(left_data);
std::fill(rbegin(output), rbegin(output) + (3 - (_bin.size() % 3)), '=');
}
return output;
}
vector<uint8_t> Base64ToBin(vector<char> const & _base64stream) {
vector<uint8_t> output;
output.reserve(_base64stream.size() * 3 / 4);
static hash_map<char, uint8_t> convert_table = {
{ 'A', 0 }, { 'B', 1 }, { 'C', 2 }, { 'D', 3 }, { 'E', 4 }, { 'F', 5 }, { 'G', 6 }, { 'H', 7 },
{ 'I', 8 }, { 'J', 9 }, { 'K', 10 }, { 'L', 11 }, { 'M', 12 }, { 'N', 13 }, { 'O', 14 }, { 'P', 15 },
{ 'Q', 16 }, { 'R', 17 }, { 'S', 18 }, { 'T', 19 }, { 'U', 20 }, { 'V', 21 }, { 'W', 22 }, { 'X', 23 },
{ 'Y', 24 }, { 'Z', 25 }, { 'a', 26 }, { 'b', 27 }, { 'c', 28 }, { 'd', 29 }, { 'e', 30 }, { 'f', 31 },
{ 'g', 32 }, { 'h', 33 }, { 'i', 34 }, { 'j', 35 }, { 'k', 36 }, { 'l', 37 }, { 'm', 38 }, { 'n', 39 },
{ 'o', 40 }, { 'p', 41 }, { 'q', 42 }, { 'r', 43 }, { 's', 44 }, { 't', 45 }, { 'u', 46 }, { 'v', 47 },
{ 'w', 48 }, { 'x', 49 }, { 'y', 50 }, { 'z', 51 }, { '0', 52 }, { '1', 53 }, { '2', 54 }, { '3', 55 },
{ '4', 56 }, { '5', 57 }, { '6', 58 }, { '7', 59 }, { '8', 60 }, { '9', 61 }, { '+', 62 }, { '/', 63 },
{ '=', 0 },
};
auto i = 0u;
for ( ; i < _base64stream.size(); i += 4) {
auto const byte1 = convert_table[_base64stream[i]];
auto const byte2 = convert_table[_base64stream[i + 1]];
auto const byte3 = convert_table[_base64stream[i + 2]];
auto const byte4 = convert_table[_base64stream[i + 3]];
output.push_back((byte1 << 2) | (byte2 >> 4));
output.push_back(((byte2 & 0x0f) << 4) | (byte3 >> 2));
output.push_back(((byte3 & 0x03) << 6) | byte4);
}
output.erase(end(output) - count(rbegin(_base64stream), rbegin(_base64stream) + 4, '='),
end(output));
return output;
}
关于Base64编码的更多相关文章
- URL安全的Base64编码
Base64编码可用于在HTTP环境下传递较长的标识信息.在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式.此时,采用Base64编码不仅比较简短,同时也具有不可 ...
- Base64编码
Base64编码 写在前面 今天在做一个Android app时遇到了一个问题:Android端采用ASE对称加密的数据在JavaWeb(jre1.8.0_7)后台解密时,居然解密失败了!经过测试后发 ...
- Android数据加密之Base64编码算法
前言: 前面学习总结了平时开发中遇见的各种数据加密方式,最终都会对加密后的二进制数据进行Base64编码,起到一种二次加密的效果,其实呢Base64从严格意义上来说的话不是一种加密算法,而是一种编码算 ...
- 网络安全——Base64编码、MD5、SHA1-SHA512、HMAC(SHA1-SHA512)哈希
据说今天520是个好日子,为什么我想起的是502.500.404这些?还好服务器没事! 一.Base64编码 Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之 ...
- Base64编码【转】
转http://www.cnblogs.com/luguo3000/p/3940197.html 开发者对Base64编码肯定很熟悉,是否对它有很清晰的认识就不一定了.实际上Base64已经简单到不能 ...
- 【前端攻略】:玩转图片Base64编码
引言 图片处理在前端工作中可谓占据了很重要的一壁江山.而图片的 base64 编码可能相对一些人而言比较陌生,本文不是从纯技术的角度去讨论图片的 base64 编码.标题略大,不过只是希望通过一些浅显 ...
- 为什么要用base64编码
1.需求 了解为什么要使用base64对数据编码 2.理由 因为传输二进制数据的时候,网络中间的有些路由会把ascii码中的不可见字符删了,导致数据不一致.一般也会对url进行base64编码 Whe ...
- 图片Base64编码
我们经常在做Jquery插件的时候需要插入一些自定义的控件,比如说按钮,而我们自己又觉着button标签很丑,而且不同浏览器显示的效果还不一样,这个时候我们需要用到图片,当然,我们可以通过img标签添 ...
- 浅析用Base64编码的图片优化网页加载速度
想必大家都知道网页加载的过程,从开始请求,到加载页面,开始解析和显示网页,遇到图片就再次向服务器发送请求,加载图片.如果图片很多的话,就会产生大量的http请求,从而影响页面的加载速度.所以现在有一种 ...
- Base64编码原理分析
Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,在了解Base64编码之前,先了解几个基本概念:位.字节. 位:"位(bit)"是计算机中最小的数据单位.每一位 ...
随机推荐
- Activiti系列:为什么Activiti 5.18 的REST的api总是返回404错误
REST api可以访问了,如下 1.修改db.properties配置文件,让他访问sql server 2.在浏览器中输入如下地址,注意中间有一个service,这点和之前的不一样,在<Ac ...
- MVC5 + EF6 + Bootstrap3 (14) 分部视图PartialView
Slark.NET-博客园 http://www.cnblogs.com/slark/p/mvc5-ef6-bs3-get-started-partialview.html 系列教程:MVC5 + E ...
- PRML读书会第一章 Introduction(机器学习基本概念、学习理论、模型选择、维灾等)
主讲人 常象宇 大家好,我是likrain,本来我和网神说的是我可以作为机动,大家不想讲哪里我可以试试,结果大家不想讲第一章.估计都是大神觉得第一章比较简单,所以就由我来吧.我的背景是统计与数学,稍懂 ...
- C#基础之lock
1.lock的本质 实现线程同步的第一种方式是我们经常使用的lock关键字,它将包围的语句块标记为临界区,这样一次只有一个线程进入临界区并执行代码.下面第一段的几行代码是关于lock关键字的使用方式, ...
- 你应当如何学习C++(以及编程)(转载)
你应当如何学习C++(以及编程)(rev#1) By 刘未鹏(pongba) C++的罗浮宫(http://blog.csdn.net/pongba) Javascript是世界上最受误解的语言,其实 ...
- Docker私有仓库Registry的搭建验证
1. 关于Registry 官方的Docker hub是一个用于管理公共镜像的好地方,我们可以在上面找到我们想要的镜像,也可以把我们自己的镜像推送上去.但是,有时候,我们的使用场景需要我们拥有一个私有 ...
- 编写高质量代码改善C#程序的157个建议[正确操作字符串、使用默认转型方法、却别对待强制转换与as和is]
前言 本文主要来学习记录前三个建议. 建议1.正确操作字符串 建议2.使用默认转型方法 建议3.区别对待强制转换与as和is 其中有很多需要理解的东西,有些地方可能理解的不太到位,还望指正. 建议1. ...
- Linq之延迟加载特性
目录 写在前面 系列文章 延迟加载 总结 写在前面 上篇文章介绍了linq中常见的几个关键字,并列举了几个例子,算是对linq如何使用有了初步了解.上篇文章中也提到了,能够使用linq的场合有一个要求 ...
- HDU 5115 Dire Wolf 区间dp
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5115 Dire Wolf Time Limit: 5000/5000 MS (Java/Others ...
- MyEclipse 启动报错:'Building workspace' has encountered a problem解决方法
转载于:http://blog.csdn.net/v123411739/article/details/42645159 每次MyEclipse工作空间报错如下:'Building workspace ...