計算機編碼規則之:Base64編碼

flydean發表於2022-04-11

簡介

我們知道計算機中的檔案可以分為兩種,一種是人肉眼可讀的文字類檔案,一種是肉眼不可讀的二進位制檔案。一般來說二進位制檔案如果用文字編輯器開啟的話會顯示亂碼,並且二進位制檔案和文字檔案的儲存和傳輸方式是不一樣的,那麼有沒有什麼辦法將二進位制檔案轉換成為文字檔案進行傳輸或者儲存呢?答案是肯定的。

這種編碼方式就是我們今天要講到的Base64編碼。

Base64和它的編碼原理

Base64是一種將二進位制編碼格式轉換為text編碼的一種形式。我們知道二進位制編碼是0和1的形式,它的單位通常是一個位元組,也就是8bits,每個bit表示的是0或者1。

而文字編碼的格式有很多種,最早也就是最簡單的編碼格式就是ASCII編碼,ASCII編碼的全稱是American Standard Code for Information Interchange,也就是美國資訊交換標準程式碼,它主要表示的是常用的一些西歐字元。

ASCII的編碼範圍是0x00-0x7F,用十進位制來表示就是0-127,總共128個字元,剛好是7bits表示的範圍。

ASCII編碼中包含了33個控制字元和95個可列印的字元,如下所示:

ASCII碼 含義ASCII碼 含義
16進位制10進位制2進位制 16進位制10進位制2進位制
0x0000NUL 空0x40641000000@
0x0111SOH 標題開始0x41651000001A
0x02210STX 正文開始0x42661000010B
0x03311ETX 正文結束0x43671000011C
0x044100EOT 傳輸結束0x44681000100D
0x055101ENQ 詢問字元0x45691000101E
0x066110ACK 承認0x46701000110F
0x077111BEL 報警0x47711000111G
0x0881000BS 退一格0x48721001000H
0x0991001HT 橫向製表0x49731001001I
0x0A101010LF 換行0x4A741001010J
0x0B111011VT 垂直製表0x4B751001011K
0x0C121100FF 走紙控制0x4C761001100L
0x0D131101CR 回車0x4D771001101M
0x0E141110SO 移位輸出0x4E781001110N
0x0F151111SI 移位輸入0x4F791001111O
0x101610000DLE 資料鏈路轉義0x50801010000P
0x111710001DC1 裝置控制10x51811010001Q
0x121810010DC2 裝置控制20x52821010010R
0x131910011DC3 裝置控制30x53831010011S
0x142010100DC4 裝置控制40x54841010100T
0x152110101NAK 否定0x55851010101U
0x162210110SYN 空轉同步0x56861010110V
0x172310111ETB 資訊組傳送結束0x57871010111W
0x182411000CAN 作廢0x58881011000X
0x192511001EM 紙盡0x59891011001Y
0x1A2611010SUB 換置0x5A901011010Z
0x1B2711011ESC 換碼0x5B911011011[
0x1C2811100FS 文字分隔符0x5C921011100\
0x1D2911101GS 組分隔符0x5D931011101]
0x1E3011110RS 記錄分隔符0x5E941011110^
0x1F3111111US 單元分隔符0x5F951011111_
0x2032100000(space)0x60961100000`
0x21331000010x61971100001a
0x22341000100x62981100010b
0x2335100011#0x63991100011c
0x2436100100$0x641001100100d
0x2537100101%0x651011100101e
0x2638100110&0x661021100110f
0x2739100111'0x671031100111g
0x2840101000(0x681041101000h
0x2941101001)0x691051101001i
0x2A42101010*0x6A1061101010j
0x2B43101011+0x6B1071101011k
0x2C44101100,0x6C1081101100l
0x2D45101101-0x6D1091101101m
0x2E46101110.0x6E1101101110n
0x2F47101111/0x6F1111101111o
0x304811000000x701121110000p
0x314911000110x711131110001q
0x325011001020x721141110010r
0x335111001130x731151110011s
0x345211010040x741161110100t
0x355311010150x751171110101u
365411011060x761181110110v
0x375511011170x771191110111w
0x385611100080x781201111000x
0x395711100190x791211111001y
0x3A58111010:0x7A1221111010z
0x3B59111011;0x7B1231111011{
0x3C60111100<0x7C1241111100\
0x3D61111101=0x7D1251111101}
0x3E62111110>0x7E1261111110~
0x3F63111111?0x7F1271111111DEL 刪除

Base64就是從ASCII編碼中挑選出64個字元和二進位制一個位元組8bits進行對映,這也就是Base64中64的含義。為什麼要選擇ASCII編碼呢?這是因為ASCII編碼是最早出現的編碼形式,幾乎所有的計算機應用都對其完全支援,不會出現資料傳輸過程中的內容轉換,非常的安全。

當然Base64編碼也有多種編碼形式,比如在MIME中,Base64選擇的是A-Z, a-z, 和 0-9 總共62個字元,再加上其他自選的兩個字元組成了64個編碼字元。

64個字元用二進位制表示是6bits,而常用的二進位制使用一個位元組來表示,也就是8bits,那麼問題來了,怎麼將8bits的二進位制用6bits的Base64字元來表示呢?

很簡單,我們只需要將3個8bits連線起來,變成24bits,這樣就可以用4個Base64來表示了。

為什麼必須對二進位制進行轉換呢?這是因為網際網路中的某些傳輸協議只支援某些特定的字符集,如果是其他的字符集是不支援的。比如說常用的傳送電子郵件的附件。因為SMTP協議最開始設計的時候是支援7 位 ASCII 字元,所以如果要傳輸檔案的話,我們需要對檔案進行編碼之後再進行傳輸。

另外Base64的一種用法就是在HTML中將圖片嵌入到網頁中,從而實現圖片的展示。

雖然Base64很好用,但是因為其只能使用6bits的字元對映集,所以會造成資料對映的損失,從而導致二進位制檔案編碼過後檔案體積變大的缺點。

Base64的變體

Base64簡單點說就是bit到bit之間的對映,那麼肯定不止一種對映方式,我們來看下Base64編碼方式的各種變體,通常來說前62位基本上是一樣的,不同之處在後面兩個字元,以及用於填充的字元(這在某些協議中可能是強制性的,或者在其他協議中可能被刪除)。

下表是常見的Base64編碼的變體:

編碼名稱編碼字元編碼字元編碼字元
第62位第63位補全符
RFC 1421: Base64 for Privacy-Enhanced Mail (deprecated)+/= mandatory
RFC 2045: Base64 transfer encoding for MIME+/= mandatory
RFC 2152: Base64 for UTF-7+/No
RFC 3501: Base64 encoding for IMAP mailbox names+,No
RFC 4648: base64 (standard)+/= optional
RFC 4648: base64url (URL- and filename-safe standard)-_= optional
RFC 4880: Radix-64 for OpenPGP+/= mandatory

Base64的編碼細節

上一節我們講到了Base64編碼的基本原則和一些常見的變體,那麼到底是如何進行對映的呢?

本節我們會以Base64的標準形式RFC 4648為例來進行詳細的講解。

RFC 4648選擇+和/這兩個字元作為編碼中的第62位和63位,並且選擇=作為補全字元。

首先來觀察一下RFC 4648的對映表:

索引二進位制字元索引二進位制Char索引二進位制Char索引二進位制Char
0000000A16010000Q32100000g48110000w
1000001B17010001R33100001h49110001x
2000010C18010010S34100010i50110010y
3000011D19010011T35100011j51110011z
4000100E20010100U36100100k521101000
5000101F21010101V37100101l531101011
6000110G22010110W38100110m541101102
7000111H23010111X39100111n551101113
8001000I24011000Y40101000o561110004
9001001J25011001Z41101001p571110015
10001010K26011010a42101010q581110106
11001011L27011011b43101011r591110117
12001100M28011100c44101100s601111008
13001101N29011101d45101101t611111019
14001110O30011110e46101110u62111110+
15001111P31011111f47101111v63111111/
補全符=

我們來以單詞man為例,來觀察一下Base64的編碼流程。

man這個單詞在ASCII中分別用77, 97和110表示,轉換成為二進位制就是01001101, 01100001 和 01101110。

將上面的三個二進位制合併在一起就成了:010011010110000101101110, 總共24-bit,從上面的表中選擇出對應的字元,所以我們可以得到man經過base64編碼之後得到:TWFu。

上面的例子中,man剛好是3個字元,也就是24個bits,可以用base64完整的表示。如果我們只有ma這兩個字元,應該怎麼進行編碼呢?

和上面一樣,ma的二進位制分別是01001101, 01100001,合併起來就是0100110101100001。

但是上面的bits只有16位,因為一個base64是6bits,所以可以用3個base64來表示,因為原始的bits少了兩位,所以用0來補全:

0100110101100001+00 = 010011010110000100。

010011010110000100轉換成為base64就是TWE,因為base64編碼需要4個字元,所以最後的字元用=來補全,也就是說me經過base64之後變成TWE=。

總結

以上就是Base64的基本含義和轉換規則,其實協議很簡單,將要轉換的資料變成二進位制,然後對照轉換表格進行轉換和補全即可。

本文已收錄於 http://www.flydean.com/18-base64-encoding/

最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!

歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!

相關文章