1. base64 用ASCII编码二进制数据
base64模块包含一些函数可以将二进制数据转换为适合使用纯文本协议传输的ASCII的一个子集。Base64、Base32、Base16和Base85编码将8位字节转换为ASCII可打印字符范围内的字符,留出更多的位来表示数据,保证与只支持ASCII数据的系统兼容,如SMTP。base(进制)值对应各编码中使用的字母表长度。这些原始编码还有一些“URL安全”(URL-safe)的变形,其使用的字母表稍有不同。
1.1 base64编码
对一些文本进行编码。
import base64 # Load this source file and strip the header. with open(__file__, 'r', encoding='utf-8') as input: raw = input.read() initial_data = raw.split('#end_pymotw_header')[1] byte_string = initial_data.encode('utf-8') encoded_data = base64.b64encode(byte_string) num_initial = len(byte_string) # There will never be more than 2 padding bytes. padding = 3 - (num_initial % 3) print('{} bytes before encoding'.format(num_initial)) print('Expect {} padding bytes'.format(padding)) print('{} bytes after encoding '.format(len(encoded_data))) print(encoded_data)
输入必须是一个字节串,所以首先将Unicode字符串编码为UTF-8。输出显示了UTF-8源文件的185个字节在编码后扩展为248字节。
393 bytes before encoding Expect 3 padding bytes 524 bytes after encoding b'JylbMV0KCmJ5dGVfc3RyaW5nID0gaW5pdGlhbF9kYXRhLmVuY29kZSgndXRmLTgnKQplbmNvZGVkX2RhdGEgPSBiYXNlNjQuYjY0ZW5jb2RlKGJ5dGVfc3RyaW5nKQoKbnVtX2luaXRpYWwgPSBsZW4oYnl0ZV9zdHJpbmcpCgojIFRoZXJlIHdpbGwgbmV2ZXIgYmUgbW9yZSB0aGFuIDIgcGFkZGluZyBieXRlcy4KcGFkZGluZyA9IDMgLSAobnVtX2luaXRpYWwgJSAzKQoKcHJpbnQoJ3t9IGJ5dGVzIGJlZm9yZSBlbmNvZGluZycuZm9ybWF0KG51bV9pbml0aWFsKSkKcHJpbnQoJ0V4cGVjdCB7fSBwYWRkaW5nIGJ5dGVzJy5mb3JtYXQocGFkZGluZykpCnByaW50KCd7fSBieXRlcyBhZnRlciBlbmNvZGluZ1xuJy5mb3JtYXQobGVuKGVuY29kZWRfZGF0YSkpKQpwcmludChlbmNvZGVkX2RhdGEp'
1.2 base64解码
b64decode()将编码的串转换回原来的形式,它取4个字节,利用一个查找表将这4个字节转换回原来的3个字节。
import base64 encoded_data = b'VGhpcyBpcyB0aGUgZGF0YSwgaW4gdGhlIGNsZWFyLg==' decoded_data = base64.b64decode(encoded_data) print('Encoded :', encoded_data) print('Decoded :', decoded_data)
编码过程中,会查看输入中的各个24位序列(3个字节),然后将这24位编码为输出中的4个字节。输出末尾插入了等号作为填充,因为在这个例子中,原始串中的位数不能被24整除。
b64decode()的返回值是一个字节串。如果已知内容是文本,那么这个字节串可以转换为一个Unicode对象。不过,由于使用base64编码的意义在于能够传输二进制数据,所以假设解码值是文本的做法并不一定安全。
1.3 URL安全的变种
因为默认的base64字母表可能使用+和/,这两个字符在URL中会用到,所以通常很有必要使用一个候选编码替换这些字符。
import base64 encodes_with_pluses = b'xfbxef' encodes_with_slashes = b'xffxff' for original in [encodes_with_pluses, encodes_with_slashes]: print('Original :', repr(original)) print('Standard encoding:', base64.standard_b64encode(original)) print('URL-safe encoding:', base64.urlsafe_b64encode(original)) print()
+替换为-,/替换为下划线(_)。除此之外,字母表是一样的。
1.4 其他编码
除了base64,这个模块还提供了一些函数来处理base85、base32和base16(十六进制)编码数据。
import base64 original_data = b'This is the data, in the clear.' print('Original:', original_data) encoded_data = base64.b32encode(original_data) print('Encoded :', encoded_data) decoded_data = base64.b32decode(encoded_data) print('Decoded :', decoded_data)
base32字母表包括ASCII集中的26个大写字母以及数字2到7。
base16函数处理十六进制字母表。
import base64 original_data = b'This is the data, in the clear.' print('Original:', original_data) encoded_data = base64.b16encode(original_data) print('Encoded :', encoded_data) decoded_data = base64.b16decode(encoded_data) print('Decoded :', decoded_data)
每次编码位数下降时,采用编码格式的输出就会占用更多空间。
base85函数使用了一个扩展的字母表,与base64编码使用的字母表相比,在空间上更节省。
import base64 original_data = b'This is the data, in the clear.' print('Original : {} bytes {!r}'.format( len(original_data), original_data)) b64_data = base64.b64encode(original_data) print('b64 Encoded : {} bytes {!r}'.format( len(b64_data), b64_data)) b85_data = base64.b85encode(original_data) print('b85 Encoded : {} bytes {!r}'.format( len(b85_data), b85_data)) a85_data = base64.a85encode(original_data) print('a85 Encoded : {} bytes {!r}'.format( len(a85_data), a85_data))
Mercurial、git和PDF文件格式中就使用了很多Base85编码和变种。Python包含两个实现,b85encode()实现了Git Mercurial中使用的版本,a85encode()实现了PDF文件中使用的Ascii85变种版本。