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遍历 truple list dictionary的几种方法总结
Sep 11 Python
Python selenium 三种等待方式详解(必会)
Sep 15 Python
python使用itchat实现手机控制电脑
Feb 22 Python
Django实战之用户认证(用户登录与注销)
Jul 16 Python
Python用61行代码实现图片像素化的示例代码
Dec 10 Python
Python实现SQL注入检测插件实例代码
Feb 02 Python
python开启debug模式的方法
Jun 27 Python
django 实现简单的插入视频
Apr 07 Python
Django ORM 查询表中某列字段值的方法
Apr 30 Python
Django filter动态过滤与排序实现过程解析
Nov 26 Python
python3 实现mysql数据库连接池的示例代码
Apr 17 Python
Python实现滑雪小游戏
Sep 25 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
php生成略缩图代码
2012/07/16 PHP
php使HTML标签自动补全闭合函数代码
2012/10/04 PHP
带密匙的php加密解密示例分享
2014/01/29 PHP
PHPMailer的主要功能特点和简单使用说明
2014/02/17 PHP
Laravel 5.4重新登录实现跳转到登录前页面的原理和方法
2017/07/13 PHP
js实现图片轮换效果代码
2013/04/16 Javascript
JS隐藏参数post传值实例
2013/04/18 Javascript
jQuery选择器全面总结
2014/01/06 Javascript
extJS中常用的4种Ajax异步提交方式
2014/03/07 Javascript
Javascript获取当前时间函数和时间操作小结
2014/10/01 Javascript
jQuery中each()方法用法实例
2014/12/27 Javascript
JavaScript中Number.MIN_VALUE属性的使用示例
2015/06/04 Javascript
js中获取时间new Date()的全面介绍
2016/06/20 Javascript
js跨域资源共享 基础篇
2016/07/02 Javascript
jquery siblings获取同辈元素用法实例分析
2016/07/25 Javascript
Node.js环境下Koa2添加travis ci持续集成工具的方法
2017/06/19 Javascript
vue中子组件调用兄弟组件方法
2018/07/06 Javascript
angular2组件中定时刷新并清除定时器的实例讲解
2018/08/31 Javascript
如何用JavaScript实现功能齐全的单链表详解
2019/02/11 Javascript
详解50行代码,Node爬虫练手项目
2019/04/22 Javascript
localstorage实现带过期时间的缓存功能
2019/06/28 Javascript
详解JavaScript 事件流
2020/09/02 Javascript
Python中的自定义函数学习笔记
2014/09/23 Python
分享一个可以生成各种进制格式IP的小工具实例代码
2017/07/28 Python
python计算两个地址之间的距离方法
2018/06/09 Python
nohup后台启动Python脚本,log不刷新的解决方法
2019/01/14 Python
应聘医药代表职位求职信
2013/10/21 职场文书
物业管理应届生求职信
2013/10/28 职场文书
法律进企业活动方案
2014/03/04 职场文书
个人委托书格式
2014/04/04 职场文书
医生个人年终总结
2015/02/28 职场文书
企业员工辞职信范文
2015/05/12 职场文书
2016年小学生新年寄语
2015/08/18 职场文书
编写python程序的90条建议
2021/04/14 Python
vue.js Router中嵌套路由的实用示例
2021/06/27 Vue.js
python unittest单元测试的步骤分析
2021/08/02 Python