前言
在編程語(yǔ)言中, 我們常常會(huì)接觸到一些二進(jìn)制數(shù)據(jù), 例如 Python 中的 Bytes 類(lèi)型數(shù)據(jù), Nodejs 中的 Buffer 類(lèi)型數(shù)據(jù). 如果不能理解二進(jìn)制數(shù)據(jù)和 unicode 數(shù)據(jù)的關(guān)系, 以及字符編碼的作用, 那么在面對(duì)一些需要進(jìn)行編碼/解碼的需求時(shí), 就會(huì)毫無(wú)思路.
由于 Python2, 3 的版本差異, 字符編碼是一個(gè)繞不開(kāi)的知識(shí)點(diǎn).
在下文中, 我會(huì)將編程語(yǔ)言中的二進(jìn)制數(shù)據(jù)和現(xiàn)實(shí)生活中的事物進(jìn)行類(lèi)比, 以達(dá)到幫助理解效果.
Python Bytes 二進(jìn)制數(shù)據(jù)和 unicode 數(shù)據(jù) - 正如罐頭和食物的關(guān)系
Python 中的 Bytes 字節(jié)類(lèi)型是存儲(chǔ)在硬盤(pán)上的二進(jìn)制數(shù)據(jù), 是由 unicode 數(shù)據(jù)經(jīng)過(guò)編碼得來(lái), 用于存儲(chǔ)和傳輸. ( 正如食物需要密封后才能保存和傳輸 )
unicode 數(shù)據(jù), 是計(jì)算機(jī)內(nèi)存中統(tǒng)一使用的數(shù)據(jù)類(lèi)型, 是內(nèi)存中運(yùn)行的程序能夠 "理解" 的數(shù)據(jù), 由 二進(jìn)制 數(shù)據(jù)解碼而來(lái). ( 正如密封的食物需要解封才能食用 )
二進(jìn)制數(shù)據(jù) 數(shù)據(jù)和 unicode 數(shù)據(jù)之間, 存在著編碼和解碼的對(duì)應(yīng)關(guān)系. 在傳輸和寫(xiě)入數(shù)據(jù)到硬盤(pán)時(shí), 都需要進(jìn)行編碼的操作. 在讀取數(shù)據(jù)時(shí), 需要進(jìn)行解碼的操作.
字符編碼就是字典
常見(jiàn)的 ASCII, UTF-8, GBK 都是在unicode數(shù)據(jù)和二進(jìn)制數(shù)據(jù)的轉(zhuǎn)換過(guò)程中所使用的編碼.
默認(rèn)地, 在讀寫(xiě)文件時(shí), 程序會(huì)根據(jù)當(dāng)前計(jì)算機(jī)系統(tǒng)使用的字符編碼來(lái)確定編碼解碼時(shí)使用的"字典".
解碼:
在讀取硬盤(pán)文件的時(shí)候, 軟件根據(jù)當(dāng)前環(huán)境使用的字符集 ("字典")將硬盤(pán)上的二進(jìn)制數(shù)據(jù)解碼 ("翻譯") 為unicode數(shù)據(jù).
編碼:
在存儲(chǔ)數(shù)據(jù)到硬盤(pán)上的時(shí)候, 軟件會(huì)根據(jù)字符集將unicode數(shù)據(jù)編碼為二進(jìn)制數(shù)據(jù).
在網(wǎng)絡(luò)傳輸數(shù)據(jù)的時(shí)候, 傳遞的也都是二進(jìn)制數(shù)據(jù).
使用一致的字符編碼是必要的
使用不一致的字符編碼就好比是我們 "拿著英漢詞典來(lái)翻譯西班牙語(yǔ)文章" .
為此我們會(huì)通過(guò) shebang 指示解釋器去使用特定的字符編碼.
-*- coding: utf-8 -*-
或者是在HTTP的響應(yīng)中指示瀏覽器數(shù)據(jù)使用的字符集
網(wǎng)絡(luò)運(yùn)輸時(shí)的序列化和反序列化 - 食物的密封和拆封
序列化
序列化是將內(nèi)存中的數(shù)據(jù) (unicode數(shù)據(jù)) 變成可存儲(chǔ)傳輸數(shù)據(jù)(二進(jìn)制數(shù)據(jù)) 的過(guò)程.
在通過(guò)網(wǎng)絡(luò)傳輸數(shù)據(jù)的時(shí)候, 我們需要首先將數(shù)據(jù)進(jìn)行序列化處理.
反序列化:
獲取到響應(yīng)數(shù)據(jù)時(shí), 需要對(duì)數(shù)據(jù)進(jìn)行反序列化處理.
字符編碼的應(yīng)用場(chǎng)景:
了解了序列化和反序列化之后, 我們就可以很容易地理解那些需要轉(zhuǎn)換數(shù)據(jù)類(lèi)型的場(chǎng)景:
- Python server socket 和 client socket 之間的數(shù)據(jù)交互:
socket.send() 只能發(fā)送bytes數(shù)據(jù) - 前端使用 Ajax 和服務(wù)器交互時(shí)需要序列化數(shù)據(jù).
- 向文件寫(xiě)入數(shù)據(jù), 讀取文件時(shí)都需要指定編碼格式.