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对字典进行排序实例
Sep 25 Python
Python中用altzone()方法处理时区的教程
May 22 Python
matplotlib绘图实例演示标记路径
Jan 23 Python
Python排序算法之选择排序定义与用法示例
Apr 29 Python
matplotlib调整子图间距,调整整体空白的方法
Aug 03 Python
python连接、操作mongodb数据库的方法实例详解
Sep 11 Python
python处理document文档保留原样式
Sep 23 Python
python-docx文件定位读取过程(尝试替换)
Feb 13 Python
python异常处理、自定义异常、断言原理与用法分析
Mar 23 Python
用 python 进行微信好友信息分析
Nov 28 Python
python二维图制作的实例代码
Dec 03 Python
Python爬虫基础初探selenium
May 31 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
模拟xcopy的函数
2006/10/09 PHP
PHP 多维数组排序(usort,uasort)
2010/06/30 PHP
一个显示效果非常不错的PHP错误、异常处理类
2014/03/21 PHP
php基于mcrypt_encrypt和mcrypt_decrypt实现字符串加密解密的方法
2016/07/12 PHP
php使用mysqli和pdo扩展,测试对比mysql数据库的执行效率完整示例
2019/05/09 PHP
JSON 学习之完全手册 图文
2007/05/29 Javascript
JQUERY操作JSON实例代码
2010/02/09 Javascript
JQUERY dialog的用法详细解析
2013/12/19 Javascript
浅析javascript中的DOM
2015/03/01 Javascript
简单谈谈JavaScript的同步与异步
2015/12/31 Javascript
jquery+json实现分页效果
2016/03/07 Javascript
详解堆的javascript实现方法
2016/11/29 Javascript
Angularjs中使用layDate日期控件示例
2017/01/11 Javascript
js实现随机数字字母验证码
2017/06/19 Javascript
Vue 中的受控与非受控组件的实现
2018/12/17 Javascript
详解VUE里子组件如何获取父组件动态变化的值
2018/12/26 Javascript
vue中选中多个选项并且改变选中的样式的实例代码
2020/09/16 Javascript
[02:35]DOTA2超级联赛专访XB 难忘一年九冠称王
2013/06/20 DOTA
Python探索之爬取电商售卖信息代码示例
2017/10/27 Python
Python遍历numpy数组的实例
2018/04/04 Python
pandas Dataframe行列读取的实例
2018/06/08 Python
详解pyppeteer(python版puppeteer)基本使用
2019/06/12 Python
Python openpyxl模块实现excel读写操作
2020/06/30 Python
解决python pandas读取excel中多个不同sheet表格存在的问题
2020/07/14 Python
使用gunicorn部署django项目的问题
2020/12/30 Python
ABOUT YOU罗马尼亚:超过600个时尚品牌
2019/09/19 全球购物
FirstCry阿联酋儿童和婴儿产品网上购物:FirstCry.ae
2021/02/22 全球购物
打造完美自荐信
2014/01/24 职场文书
优秀交警事迹材料
2014/01/26 职场文书
项目投资意向书
2014/04/01 职场文书
职业规划实施方案
2014/06/10 职场文书
建筑施工安全责任书
2014/07/24 职场文书
党的群众路线教育实践活动总结
2014/10/30 职场文书
幼儿园教师求职信
2015/03/20 职场文书
Golang的继承模拟实例
2021/06/30 Golang
Android开发之WECHAT微信小程序路由跳转的两种形式
2022/04/12 Java/Android