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\n'.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'\xfb\xef' encodes_with_slashes = b'\xff\xff' 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變種版本。