# 簡(jiǎn)介
Base64是一種用64個(gè)字符來表示任意二進(jìn)制數(shù)據(jù)的方法愈案。是一種編碼方法银萍,有自己的編碼表
,所以稱為Base64肥隆,是因?yàn)槠涫褂?4個(gè)字符來對(duì)任意數(shù)據(jù)進(jìn)行編碼既荚,同理有Base32、Base16編碼栋艳。
用記事本打開exe
恰聘、jpg
、pdf
這些文件時(shí)吸占,我們都會(huì)看到一大堆亂碼晴叨,因?yàn)槎M(jìn)制文件包含很多無法顯示和打印的字符(ASCII表中有32個(gè)非打印控制字符
),所以矾屯,如果要讓記事本這樣的文本處理軟件能處理二進(jìn)制數(shù)據(jù)兼蕊,就需要一個(gè)二進(jìn)制到字符串的轉(zhuǎn)換方法。Base64是一種最常見的二進(jìn)制編碼方法件蚕。
# 應(yīng)用場(chǎng)景
應(yīng)用:
- 有些文本協(xié)議不支持不可見字符的傳遞孙技,只能用ASCII編碼表中大于32的可見字符來傳遞信息(協(xié)議規(guī)定)
- 比如一個(gè)純文本協(xié)議,二進(jìn)制中可能會(huì)出現(xiàn)被當(dāng)做控制字符處理的部分骤坐。這樣引起傳輸失敗绪杏。
- 比如http協(xié)議當(dāng)中的key value字段,必須進(jìn)行URLEncode纽绍,不然出現(xiàn)的等號(hào)可能使解析失敗。同時(shí)空格也會(huì)使http請(qǐng)求解析出現(xiàn)問題势似,比如 請(qǐng)求行就是以空格來劃分的
- 在網(wǎng)絡(luò)上交換數(shù)據(jù)時(shí)拌夏,比如說從A地傳到B地,往往要經(jīng)過多個(gè)路由設(shè)備履因,由于不同的設(shè)備對(duì)字符的處理方式有一些不同障簿,這樣那些不可見字符就有可能被處理錯(cuò)誤,這是不利于傳輸?shù)恼てO劝褦?shù)據(jù)先做一個(gè)Base64編碼站故,統(tǒng)統(tǒng)變成可見字符,這樣出錯(cuò)的可能性就大降低了毅舆。
對(duì)證書來說西篓,特別是根證書,一般都是作Base64編碼的憋活,因?yàn)樗诰W(wǎng)上被許多人下載岂津。電子郵件的附件一般也作Base64編碼的,因?yàn)橐粋€(gè)附件數(shù)據(jù)往往是有不可見字符的悦即。 - 有時(shí)在一些特殊應(yīng)用的場(chǎng)合吮成,大多數(shù)消息是純文本的橱乱,偶爾需要用這條純文本通道傳一張圖片之類的情況發(fā)生的時(shí)候,就會(huì)用到base64
- 某些系統(tǒng)中只能使用ASCII字符粱甫。Base64就是用來將非ASCII字符的數(shù)據(jù)轉(zhuǎn)換成ASCII字符的一種方法泳叠。
# 原理
Base64的原理很簡(jiǎn)單,首先茶宵,準(zhǔn)備一個(gè)包含64個(gè)字符的數(shù)組:
['A', 'B', 'C', ... 'a', 'b', 'c', ... '0', '1', ... '+', '/']
然后危纫,對(duì)二進(jìn)制數(shù)據(jù)進(jìn)行處理,每3個(gè)字節(jié)一組节预,一共是3x8=24
bit叶摄,劃為4組,每組正好6個(gè)bit:
這樣我們得到4個(gè)數(shù)字作為索引安拟,然后查表蛤吓,獲得相應(yīng)的4個(gè)字符,就是編碼后的字符串糠赦。
所以会傲,Base64編碼會(huì)把3字節(jié)的二進(jìn)制數(shù)據(jù)編碼為4字節(jié)的文本數(shù)據(jù),長(zhǎng)度增加33%拙泽,好處是編碼后的文本數(shù)據(jù)可以在郵件正文淌山、網(wǎng)頁(yè)等直接顯示。
注意點(diǎn):
- 如果要編碼的二進(jìn)制數(shù)據(jù)不是3的倍數(shù)顾瞻,最后會(huì)剩下1個(gè)或2個(gè)字節(jié)怎么辦泼疑?Base64用
\x00
字節(jié)在末尾補(bǔ)足后,再在編碼的末尾加上1個(gè)或2個(gè)=
號(hào)荷荤,表示補(bǔ)了多少字節(jié)退渗,解碼的時(shí)候,會(huì)自動(dòng)去掉蕴纳。
# 舉例:原字符串a(chǎn)bcd
# 二進(jìn)制形式(因?yàn)槟?之后会油,剩1一個(gè)字節(jié),所以需要補(bǔ)兩個(gè)字節(jié))
01100001 01100010 01100011 01100100 00000000 00000000
# 每3個(gè)字節(jié)一組古毛,劃分為4組翻翩,每組6bit
011000 010110 001001 100011 011001 000000 000000 000000
24 22 9 35 25 0
Y W J j Z A
# 需要注意,因?yàn)槲覀冄a(bǔ)了兩個(gè)字節(jié)稻薇,所以最后必然會(huì)有兩組000000嫂冻,注意,此處000000不會(huì)編碼為A颖低,而是記為=絮吵,標(biāo)志著我們?cè)谀┪惭a(bǔ)充了2個(gè)`\x00`
# 所以最后的結(jié)果為:
YWJjZA==
# 同理:當(dāng)我們補(bǔ)了1個(gè)字節(jié)時(shí),最后必然會(huì)有一組000000忱屑,此處000000也是記為=蹬敲,標(biāo)志著我們?cè)谀┪惭a(bǔ)充了1個(gè)`\x00`
abcde 編碼為 -> YWJjZGU=
由于
=
字符也可能出現(xiàn)在Base64編碼中暇昂,但=
用在URL、Cookie里面會(huì)造成歧義伴嗡,所以急波,很多Base64編碼后會(huì)把=
去掉。
去掉=
后怎么解碼呢瘪校?因?yàn)锽ase64是把3個(gè)字節(jié)變?yōu)?個(gè)字節(jié)澄暮,所以,Base64編碼的長(zhǎng)度永遠(yuǎn)是4的倍數(shù)阱扬,因此泣懊,需要加上=
把Base64字符串的長(zhǎng)度變?yōu)?的倍數(shù),就可以正常解碼了麻惶。由于標(biāo)準(zhǔn)的Base64編碼后可能出現(xiàn)字符
+
和/
馍刮,在URL中就不能直接作為參數(shù),所以又有一種"url safe"
的base64編碼窃蹋,其實(shí)就是把字符+
和/
分別變成-
和_
:
比如:有些平臺(tái)上用的Base64 URL 是標(biāo)準(zhǔn)Base64編碼的一個(gè)變種卡啰,分別用 -、_ 替換標(biāo)準(zhǔn)Base64編碼結(jié)果中的 + 警没、 / 匈辱,并刪除結(jié)果最后的 =還可以自己定義64個(gè)字符的排列順序,這樣就可以自定義Base64編碼杀迹,不過亡脸,通常情況下完全沒有必要。
Base64是一種通過查表的編碼方法树酪,不能用于加密梗掰,即使使用自定義的編碼表也不行。適用于小段內(nèi)容的編碼嗅回,比如數(shù)字證書簽名、Cookie的內(nèi)容等摧茴。
# iOS中的Base64
//字符串 base64編碼
//UTF8字符串——data——base64編碼字符串
NSString *target = @"Hello!";
NSData *data = [target dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64Str = [data base64EncodedStringWithOptions:0];
//UTF8字符串——data——base64绵载、UTF8編碼格式的data——base64編碼字符串
NSData * base64Data = [nsdata base64EncodedDataWithOptions:0];
NSString *ret = [[NSString alloc] initWithData:base64Data encoding:NSUTF8StringEncoding];
#pragma mark -- 關(guān)于base64EncodedDataWithOptions方法生成的Base-64, UTF-8 encoded NSData
/* Create a Base-64, UTF-8 encoded NSData from the receiver's contents using the given options.
*/
- (NSData *)base64EncodedDataWithOptions:(NSDataBase64EncodingOptions)options API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0));
從方法說明中可以看到,生成的是base64苛白、UTF8編碼的字節(jié)數(shù)組娃豹。
比如:@“hello!” 轉(zhuǎn)成NSData對(duì)象
對(duì)應(yīng)的字節(jié)數(shù)組是 <48656c6c 6f21>(十六進(jìn)制)
進(jìn)行base64編碼
按照上面的過程,結(jié)果字節(jié)數(shù)組是<18 06 21 44 27 06 60 33>(十進(jìn)制表示购裙,方便查Base64編碼表)懂版,對(duì)應(yīng)的字符串是SGVsbG8h
而使用上面的iOS api,得到的字節(jié)數(shù)組是 <83 71 86 115 98 71 56 104>(十進(jìn)制表示躏率,方便查UTF8編碼表)躯畴,對(duì)應(yīng)的字符串是SGVsbG8h
# 小結(jié)
Base64是一種任意二進(jìn)制到文本字符串的編碼方法民鼓,適用于小段內(nèi)容的編碼,常用于在URL蓬抄、Cookie丰嘉、網(wǎng)頁(yè)中傳輸少量二進(jìn)制數(shù)據(jù)(如數(shù)字證書簽名、Cookie的內(nèi)容等)嚷缭。
與UTF在使用上有明顯的不同饮亏,要在多語(yǔ)言環(huán)境中通用,那就是要使用UTF阅爽,這可以理解為存儲(chǔ)數(shù)據(jù)格式路幸。用了UTF是讓大家都能識(shí)別數(shù)據(jù),不然就會(huì)亂碼付翁。
Base-64的話简肴,不是底層存儲(chǔ)格式,只是為了數(shù)據(jù)交換用胆敞。比如圖片變成字符格式着帽,這是一種應(yīng)用格式
# 參考鏈接
原文鏈接:廖雪峰的官方網(wǎng)站,本文增加了一些個(gè)人理解及iOS相關(guān)API