Python使用base64模块进行二进制数据编码详解


Posted in Python onJanuary 11, 2018

前言

昨天团队的学妹来问关于POP3协议的问题,所以今天稍稍研究了下POP3协议的格式和Python里面的poplib。而POP服务器往回传的数据里有一部分需要用到Base64进行解码,所以就顺便看了下Python里面的base64模块。

本篇先讲一下base64模块,该模块提供了关于Base16,Base32,Base64,Base85和Ascii85的编码和解码相关的函数。有关poplib模块的内容,会在后面发上来。嗯,又挖了一个坑,这辈子挖的坑填不完了...

以下内容摘自http://bbs.chinaunix.net/thread-1150250-1-1.html,详细说明了为什么回传的数据会先经过Base64编码:

由於歷史原因,Internet上有些郵件系統只支援7Bit的字元傳輸,而漢字的內碼是8Bit的,當在電子郵件中發送中文時,如果經過這些只支援7Bit字元的郵件系統,便會將漢字內碼的第八位元的1全部變成0。
以”中文”兩字為例,HEX為A4A4A4E5,當最高位元被清掉時就會變成24242465,也就是”$$$e”。telnet也存在這樣子的問題。

除了中文郵件外,使用電子郵件傳送圖片、程式、壓縮文件等也會發生這個問題。所以在電子郵件中一般採用各種郵件編碼方式來解決這個問題,將8Bit按照一定的規則進行編碼,便可以完好地通過只支持7Bit字元的郵件系統。

常見的郵件編碼有UU與MIME,而MIME(Multipurpose Internet Mail Extentions)一般翻譯成「多媒體傳送模式」,顧名思義,它標榜的就是可以傳送多媒體型式的檔案,可以在一封mail中附加各種型式檔案一起送出。

MIME定義兩種編碼方法:Base64與QP(Quote-Printable),兩者使用時機不同,QP的規則是對於資料中的7bits無須重複encode,僅8bits資料轉成7bits。QP編碼適用於非US-ASCII的文字內容,例如我們的中文檔案,而Base64的編碼規則,是將整個檔案重新編碼,編成7bits,它是用於傳送binary檔案時使用。由於編碼的方式不同,會影響編碼之後的檔案大小。有些較懶惰的軟體便都一律採用Base64編碼了。

Base64

base64模块提供了6个函数用于Base64的编码和解码,可以将他们分为三组。

base64.b64encode(s, altchars=None)
base64.b64decode(s, altchars=None, validate=False)

参数s代表需要编码/解码的数据。其中b64encode的参数s的类型必须是字节包(bytes)。b64decode的参数s可以是字节包(bytes),也可以是字符串(str)。

由于Base64编码后的数据中可能会含有'+'或者'/'两个符号,如果编码后的数据用于url或者文件系统的路径中,就可能会导致Bug。所以base64模块提供了将编码后的数据中'+'和'/'进行替换的方法。

参数altchars必须是长度为2的字节包,这两个符号会用于替换编码后数据中的'+'和'/'。这个参数默认是None。

参数validate默认为False。如果它为True时,base64模块在进行解码前会先检查s中是否有非base64字母表中的字符,如果有的话则抛出错误binascii.Error: Non-base64 digit found。

如果数据的长度不正确则会抛出错误binascii.Error: Incorrect padding。

>>> import base64
>>> x = base64.b64encode(b'test')
>>> x
b'dGVzdA=='
>>> base64.b64decode(x)
b'test'

base64.standard_b64encode(s)
base64.standard_b64decode(s)

这组函数会直接将参数s传到上一组函数中。

base64.urlsafe_b64encode(s)
base64.urlsafe_b64decode(s)

这组函数同样基于第一组函数,但进行编码后会将输出数据中的'+'和'/'替换为'-‘和'_'。解码前则将数据中的'-‘和'_'替换为'+'和'/'。

另,Base64编码还会产生一个符号'=',这个符号用于将数据长度填充到4的倍数。

Base32

base64.b32encode(s)
base64.b32decode(s, casefold=False, map01=None)

参数s与Base64一致。

Base32编码后的字符范围为[2-7A-Z],是不支持小写字母的。不过当参数casefold为True时,Base32解码时可以接受小写字母的输入。但是为了安全考虑,这个参数默认为False。

Base32的解码同时还允许将数字0替换为大写字母O,把数字1替换为大写字母I或者L。参数map01可以指定将数字1替换为哪个字符(源码中并没有限定必须是字母I或者L其中之一),当这个参数非None时,数字0总是会被替换为字母O。同样为了安全考虑,这个参数默认为None。

Base16

base64.b16encode(s)
base64.b16decode(s, casefold=False)

Base16编码后的字符范围为[0-9A-F]。

参数s和casefold的作用与Base32一致。

Base85

base64.b85encode(b, pad=False)
base64.b85decode(b)

参数b为用于编码/解码的数据,类型要求跟Base64的参数s一致。

参数pad为True时,在编码前会用b'\0'将数据填充到长度为4的倍数。不过在解码的时候不会移除这些填充数据。

这组函数是在Python3.4之后新增的。

Ascii85

base64.a85encode(b, *, foldspaces=False, wrapcol=0, pad=False, adobe=False)

参数b为用于编码的数据,类型必须为bytes。

参数foldspaces为True时会用b'y'来表示4个连续的空格。

参数wrapcol为一个整数,当wrapcol非0时,这个整数控制编码后的输出每多少个字符添加一个换行符b'\n'。

参数pad为True时,数据在编码前会用b'\0'填充到长度为4的倍数。解码的时候不会移除这些填充数据。

参数adobe指定了数据是否采用Adobe的格式。Adobe Ascii85的编码数据由<\~和\~>包围起来,如果这个参数为True,返回的数据会加上这对符号。

base64.a85decode(b, *, foldspaces=False, adobe=False, ignorechars=b' \t\n\r\v')

参数b为用于编码的数据,类型可以为bytes或者str。

参数foldspaces为True时会用b'y'来表示4个连续的空格。

参数adobe指定了数据是否采用Adobe的格式。Adobe Ascii85的编码数据由<\~和\~>包围起来,如果这个参数为True,解码前base64会先去掉这对符号。

参数ignorechars指定了解码时需要忽略掉的字符。默认包含了ASCII中所有的空白符。

这组函数是在Python3.4之后新增的。

base64模块的官方文档中提到:Base85和Ascii85使用5个字符编码4个字节,而Base64使用6个字符编码4个字节(实际上是4个字符编码3个字节),当空间不充裕时前两者会比Base64更高效。

旧API

base64仍然保留了一部分旧的API,用于一些特殊用途。

base64.encode(input, output)
base64.decode(input, output)

这组函数使用二进制文件作为数据源,并将编码/解码后的数据写入二进制文件。

base64.encodebytes(s)
base64.decodebytes(s)

encodebytes和b64encode在内部都是调用的binascii模块的b2a_base64,只不过encodebytes调用b2a_base64时newline参数使用默认值True。也就是说,encodebytes在输出数据的时候,每76个字节会添加一个换行符b'\n'。

decodebytes和默认参数下的b64decode基本一致。只有参数类型的检查不一样,decodebytes只支持bytes类型的数据。

base64.encodestring(s)
base64.decodestring(s)

这组函数在Python3.1之后就废弃了,目前会直接调用上一组函数。

总结

base64模块提供了对二进制数据进行编码的接口,其中包括了标准的Base64,Base32,Base16和事实标准Ascii85和Base85。通过学习这个模块,顺便学习了一下二进制数据编码的各种细节,感受颇深。有时候我们自以为了解计算机,了解互联网,其实每个人看到的都只是沧海一粟,不值一提。这个领域对于我来说还有很多未知,是等待探索的,而我也不会停止探索的脚步。

以上就是本文关于Python使用base64模块进行二进制数据编码详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

Python 相关文章推荐
python中的一些类型转换函数小结
Feb 10 Python
python查看zip包中文件及大小的方法
Jul 09 Python
在Django框架中伪造捕捉到的URLconf值的方法
Jul 18 Python
Python+Django搭建自己的blog网站
Mar 13 Python
Python爬虫框架scrapy实现downloader_middleware设置proxy代理功能示例
Aug 04 Python
python实现两个文件夹的同步
Aug 29 Python
python 动态迁移solr数据过程解析
Sep 04 Python
python使用opencv实现马赛克效果示例
Sep 28 Python
Python 实现递归法解决迷宫问题的示例代码
Jan 12 Python
解决Jupyter Notebook开始菜单栏Anaconda下消失的问题
Apr 13 Python
django数据模型中null和blank的区别说明
Sep 02 Python
在 Python 中使用 7zip 备份文件的操作
Dec 11 Python
Python实现备份MySQL数据库的方法示例
Jan 11 #Python
教你用Python写安卓游戏外挂
Jan 11 #Python
python实现学生管理系统
Jan 11 #Python
linecache模块加载和缓存文件内容详解
Jan 11 #Python
Python实现将MySQL数据库表中的数据导出生成csv格式文件的方法
Jan 11 #Python
python+django+sql学生信息管理后台开发
Jan 11 #Python
hmac模块生成加入了密钥的消息摘要详解
Jan 11 #Python
You might like
SONY ICF-F10中波修复记
2021/03/02 无线电
PHP去除数组中重复的元素并按键名排序函数
2008/08/18 PHP
PHP面向对象的进阶学习(抽像类、接口、final、类常量)
2012/05/07 PHP
php compact 通过变量创建数组
2016/11/15 PHP
PHP中抽象类,接口功能、定义方法示例
2019/02/26 PHP
有一段有意思的代码-javascript现实多行信息
2007/08/26 Javascript
仅IE6/7/8中innerHTML返回值忽略英文空格的问题
2011/04/07 Javascript
基于jQuery的360图片展示实现代码
2012/06/14 Javascript
JavaScript面向对象(极简主义法minimalist approach)
2012/07/17 Javascript
JavaScript操作XML/HTML比较常用的对象属性集锦
2015/10/30 Javascript
JS动态创建元素的两种方法
2016/04/20 Javascript
Angular懒加载机制刷新后无法回退的快速解决方法
2016/08/30 Javascript
基于jQuery实现的打字机效果
2017/01/16 Javascript
js中开关变量使用实例
2017/02/24 Javascript
详解jQuery中关于Ajax的几个常用的函数
2017/07/17 jQuery
JavaScript中的高级函数
2018/01/04 Javascript
微信小程序实现录音时的麦克风动画效果实例
2019/05/18 Javascript
详解利用nodejs对本地json文件进行增删改查
2019/09/20 NodeJs
JavaScript代码简化技巧实例解析
2020/09/09 Javascript
[02:09]抵达西雅图!中国军团加油!
2014/07/07 DOTA
[02:38]DOTA2亚洲邀请赛小组赛精彩集锦:Wings完美团击溃对手
2017/03/29 DOTA
haskell实现多线程服务器实例代码
2013/11/26 Python
从零学python系列之数据处理编程实例(二)
2014/05/22 Python
快速入门python学习笔记
2017/12/06 Python
基于Django的ModelForm组件(详解)
2017/12/07 Python
python hough变换检测直线的实现方法
2019/07/12 Python
Python实现将蓝底照片转化为白底照片功能完整实例
2019/12/13 Python
Python表达式的优先级详解
2020/02/18 Python
python 基于opencv实现图像增强
2020/12/23 Python
HTML5 canvas基本绘图之绘制阴影效果
2016/06/27 HTML / CSS
2013年办公室秘书的个人自我鉴定
2013/10/24 职场文书
网页美工求职信
2014/02/15 职场文书
老同学聚会感言
2014/02/23 职场文书
上班时间打瞌睡检讨书
2014/09/26 职场文书
自主招生学校推荐信范文
2015/03/26 职场文书
《生物入侵者》教学反思
2016/02/16 职场文书