前言

昨天团队的学妹来问关于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模块进行二进制数据编码详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!

稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!

昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。

这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。

而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?