Python通用程式設計 - 第四章:字元編碼

yitema01發表於2019-04-04

本文是Python通用程式設計系列教程,已全部更新完成,實現的目標是從零基礎開始到精通Python程式語言。本教程不是對Python的內容進行泛泛而談,而是精細化,深入化的講解,共5個階段,25章內容。所以,需要有耐心的學習,才能真正有所收穫。雖不涉及任何框架的使用,但是會對作業系統和網路通訊進行全域性的講解,甚至會對一些開源模組和伺服器進行重寫。學完之後,你所收穫的不僅僅是精通一門Python程式語言,而且具備快速學習其他程式語言的能力,無障礙閱讀所有Python原始碼的能力和對計算機與網路的全面認識。對於零基礎的小白來說,是入門計算機領域並精通一門程式語言的絕佳教材。對於有一定Python基礎的童鞋,相信這套教程會讓你的水平更上一層樓。

一 理解字元編碼理論儲備知識

1. 字元編碼說明

字元編碼這個知識點其實只是涉及到一行程式碼,但是它非常重要,據不完全統計,現在軟體30%的損失都是由於亂碼問題所導致的,這個問題是最容易被大家所忽視的,因為使用的時候只是一行程式碼的問題,但是它的裡面包含很多的知識,大部分人更加傾向於直接掌握結果,而不考慮它內部的知識,這就導致了一旦遇到字元編碼的亂碼問題,就會手足無措。你之前可能看過一下相關的介紹,也可能聽過一些歪理邪說,這些介紹是否正確我們無從考證,在這篇文章中,我們會對字元編碼進行全方位的介紹。字元編碼的特點是理論非常多,而結論非常少,但是如果不知道理論,結論可能永遠也無法理解,而且以後遇到字元編碼問題就會不知所措。目前在網上幾乎沒有人能夠清晰的把它說明白,因為字元編碼的發展史涵蓋了整個計算機發展的過程,我們不會直接拿出現成的結論或者猜測的結論,而是會從客觀展示出來的列印結果來論證:我所講的就是正確的。

2. 計算機執行應用軟體原理

在正式介紹字元編碼之前,我們需要先了解計算機的執行與哪些核心部件相關:

CPU:執行程式 記憶體:臨時儲存資料,一個軟體要想執行,必先載入到記憶體 硬碟:軟體的資料要想永久儲存,一定要存入硬碟

如下圖所示,一個應用軟體的啟動過程是:

  1. 應用軟體存放於硬碟上
  2. 應用軟體程式從硬碟讀入到記憶體
  3. CPU呼叫記憶體中與該應用軟體相關的資料進行處理

應用軟體啟動過程

3. 儲存檔案的原理

接下里來我們再來看一下一個文字編輯器儲存檔案的過程:

  1. 如下圖所示,當我啟動notepad++程式之後,就是把這個程式讀入到記憶體
  2. 我在notepad++程式中輸入“Hello World”之後,這個內容臨時儲存到了記憶體中
  3. 你現在看到的螢幕上的內容是,notepad++程式在你寫入的同時返回的結果

存在記憶體中的特點是:只要一斷電,資料就會丟失,所以,我們要想永久的儲存資料,需要在notepad++程式上執行一個操作,把資料永久儲存到硬碟(notepad++程式會給你附加一個自動儲存到硬碟的功能,這是為了提升使用者的使用體驗,早期的程式沒有這個功能)。

儲存檔案

4. 執行Python程式的原理

接下來我們再來看一下Python直譯器執行Python程式的原理,也是分為三個階段(以Python3直譯器和test.py檔案為例):

  1. 先啟動Python直譯器(把Python3直譯器這個應用軟體讀入記憶體)
  2. 把test.py檔案讀入記憶體
  3. Python3直譯器識別Python語法,解釋執行test.py程式

注意:我們寫的Python程式碼如果沒有直譯器解釋執行和寫一個普通的檔案沒有任何區別,這也就是說,你可以使用Pycharm寫Python程式碼,也可以使用WPS寫Python程式碼,在編寫Python程式時候沒有語法的概念(檢測語法Pycharm給你附加的功能,但其實本質也是一個文字編輯器),編寫的結果和編寫一個普通檔案是沒有任何區別的, 只有在第三階段執行Python程式的時候才會監測語法。

二 字元編碼介紹

1. 字元編碼初次登場

計算機是基於電工作的, 高電平用數字1表示,低電平用數字0表示,計算機也只能識別010101這種東西,這就是二進位制,計算機的工作原理就是基於二進位制工作的。 我們平時在使用計算機的時候並不是使用二進位制控制的,使用的都是人類的字元(中國人使用漢語,美國人使用英語),但是這些人類的字元計算機是看不懂的,要想讓計算機能夠看得懂,必先經歷一個過程:

人類的字元====>翻譯====>二進位制數字

我們在notepad++程式中寫了一個“你好”,就把這個內容寫入到了記憶體中,計算機要想識別必先經歷一個翻譯的過程,這個翻譯肯定不能隨便翻譯的,因為在取這個資料的時候仍需按照二進位制數字與人類的字元一一對應的取出來,所以必須要遵循一個標準,這個標準就是字元編碼表。
我們在notepad++程式中寫了一個“Hello World”,在計算機內部已經事先存好了這張表,每一個字母(包含大寫字母和小寫字母)和空格回撤標點符號這些東西都對應一個數字,然後再把這些數字轉化成二進位制,這樣一個字元就會對應一組二進位制數字,也就完成了寫入的過程,當列印的時候再反過來,一組二進位制數字對應一個字元。所以,我們就清楚了記憶體上應該有這樣一張字元編碼表,早期的時候硬碟上儲存的也是二進位制,所以硬碟上無需有字元編碼表。

2. 字元編碼發展史

計算機起源於美國,美國人說英語,美國人當時設計的時候根本就沒考慮過中國人有一天也能用的起計算機,那麼當時美國人設計的時候就只需要考慮計算能識別英文符號就可以了,所以當時的字元編碼表就只是英文字元與數字的對應關係,所有這些加起來一共120多種就夠了,那麼也就應該有120多個不同的數字來表示這些字元。計算機的數字是二進位制的,要想用010101這種東西表示出120多個數字應該用幾位二進位制數?

一位二進位制數:只能表示0或者1兩個數字,除去0之外,只能表示1個數字 兩位二進位制數:00,01,10,11能表示3個數字 三位二進位制數:000,001,010,011,100,101,110,111能表示7個數字 四位二進位制數:能表示2**4-1 = 15個數字

最開始設計的時候設計了八位二進位制數,最小的是0000 0000,最大的是1111 1111,它能夠表示2 * * 8 - 1 = 255個數字(不包含0),但是最早期只是使用了後面的七位二進位制位能夠表示1~127的數字就夠了,留下一位二進位制位為了以後的擴充套件留一些餘地。一個二進位制位稱為一個位元位,8個位元位稱為一個位元組:8bit = 1bytes,美國人用8個位元位來表示一個英文字元,所以一個英文字元佔一個位元組。這個字元編碼表就是ASCII表,這也是最早的字元編碼表,如下圖所示。

1111.jpg
後來中國人也開始使用計算機了,ASCII只有英文字元的對應關係,而且8個位元位最多能表示200多個字元的對印關係,如果有一個人說他認識200多個漢字,估計這個人小學還未畢業。在這樣的場景下,中國人也定製出了自己的字元編碼表,叫做GBK(gb2312),為了表示出更多的數字,GBK編碼表用16個位元位來表示一箇中文字元,那麼他所能表示的漢字個數就是2 * * 16 - 1 = 65535個,這個基本上也就涵蓋了所有我們常用的漢字。所以GBK使用兩個位元組來表示一箇中文字元,但是GBK來表示一個英文字元還是用一個位元組(為了和ASCII統一)。

不只是中國人能用電腦,日本人和韓國人也能用電腦,日本人規定了自己的Shift_JIS編碼,韓國人規定了自己的Euc-kr編碼(另外,韓國人說,計算機是他們發明的,要求世界統一用韓國編碼,但世界人民沒有搭理他們)。

到了這個階段,如果每個國家的東西都是自己國家的人看,這當然沒有問題,但是顯然我們有這樣的需求,這就出現了一個問題,你的硬碟上可能有日本人和韓國人編碼的軟體,但是記憶體中的字元編碼表只有GBK,那麼就會出現亂碼,你不是秦始皇,自然做不出他那麼偉大是事情,所以必須找到一種能夠相容萬國語言的字元編碼(其實6萬多就足夠表示了,各國語言雖然不同,但是所用的符號都非常類似),這個字元編碼就是Unicode,它使用16個位元位也就是兩個位元組來表示一個字元。這也就意味著任何國家的資料到了記憶體中都是Unicode編碼,這樣記憶體中就不會出現亂碼的問題了。除此之外還有一個很重要的問題,之前用各國編碼寫的儲存在硬碟上的檔案不能廢棄,這是歷史遺留問題,所以Unicode還必須要有一個非常重要的功能:把各國編碼的檔案轉化成Unicode,如下圖所以。這樣有了Unicode之後,一方面可以相容萬國語言,另一方面老的軟體也可以在不同國家的機器上執行。

unicode轉化過程
至此,Unicode字元編碼已經解決的大部分的亂碼問題,但是還存在一個可以優化的空間,記憶體中用Unicode編碼,硬碟上面有各國編碼的軟體,以後寫程式肯定是趨向於全部使用Unicode編碼,但是如果一篇文件當部分都是英文,寫一個同樣的內容原來的ASCII一個英文字元佔用一個位元組,而Unicode一個英文字元就會佔用兩個位元組,這樣的話就會增加硬碟的佔用並且加大了IO操作的時間(IO操作暫且先理解為讀寫操作,後面會有詳細說明)。本著節約的精神,又出現了把Unicode編碼轉化為“可變長編碼”的UTF-8(可變長,全稱Unicode Transformation Format)編碼。UTF-8編碼把一個Unicode字元根據不同的數字大小編碼成1-6個位元組,常用的英文字母被編碼成1個位元組,漢字通常是3個位元組,只有很生僻的字元才會被編碼成4-6個位元組。如果你要傳輸的文字包含大量英文字元,用UTF-8編碼就能節省空間。所以,現在硬碟上的字元編碼一般是“UTF-8”,記憶體中用的字元編碼一般是Unicode,以後肯定會趨向於記憶體和硬碟的儲存都是用UTF-8這種字元編碼,但是現階段都是被逼的,Unicode編碼還要負責轉換歷史遺留問題的編碼。

三 亂碼問題的產生與解決

1. 亂碼問題的成因

接下來就是我們做實驗的過程了,記憶體中的編碼都是Unicode,如果忽略硬碟,在記憶體中隨便些什麼編碼都不會出現亂碼,但是因為硬碟的存在就會出現由記憶體向硬碟儲存的時候你要指定一個字元編碼,比如說是GBK,這時就是由Unicode轉化稱GBK,當把這個硬碟檔案重新在記憶體讀取的時候你也要告訴計算機按照GBK編碼來讀取,它才會對應的把資料由GBK編碼反解成Unicode編碼寫入到記憶體。如果你在這時告訴你計算機用ASCII的標準來反解資料,那麼就無法反解出原來儲存的資料內容,計算機蒙圈了,呈現給你的就是它蒙圈後的結果。

2. 保證不亂碼的方案

保證不出現亂碼問題其實結論就只有一個:檔案用什麼編碼儲存的,就用什麼編碼讀取,注意:我們能控制的只是檔案由記憶體儲存到硬碟的編碼。

3. 人為製造亂碼

接下來我們會在notepad++程式上演示人為製造亂碼的過程,首先把程式儲存檔案的編碼改成日文的編碼,然在在程式裡面先後寫入中文的“你瞅啥”和日文的“あなたを見て”(這是日文的“瞅你咋地”),接下里來儲存。注意:在儲存過程中,其實計算機已經不能識別中文的“你瞅啥”了,但是它不能報錯呀,他一定要硬存,所以這個儲存的過程並沒有什麼問題,你現在看到的結果還是在記憶體中的。

亂碼問題
儲存之後,我們關掉再重新讀取,先使用使用ASCII試一下會看到什麼結果。
亂碼問題

全都是亂碼,那麼我們再改成日文的編碼試試。
亂碼問題
日文“瞅你咋地”已經讀取出來了,但是我們存的漢字就讀不出來了,這時無論我們改成任何編碼漢字都是讀不出來的,因為儲存的時候計算機就已經無法識別了,他並沒有完成有效的資料儲存。所以,以後寫程式寫檔案都應該用UTF-8編碼來寫,這樣就不會發生亂碼了。

四 Python中的字元編碼問題

1. 直譯器讀取檔案時字元編碼異同

我們現在用GBK編碼在檔案中寫一個“你好”,然後用Python直譯器來解釋執行(不用Pycharm),你會發現在Python2 和Python3 中分別提示以下錯誤資訊,如下圖所示,這就說明如果你不指定字元編碼:

Python3直譯器預設使用UTF-8編碼來讀 Python2直譯器預設使用ASCII來讀

image.png
為了解決這個問題,我們需要在寫Python檔案開頭就指定好字元編碼,如下圖所示。
image.png
再次呼叫直譯器解釋執行的時候就不會發生字元編碼的錯誤了。
image.png
檔案頭的作用就是告訴Python直譯器用指定的字元編碼去讀取檔案內容。 在Pycharm中,當我指定好了讀取檔案的字元編碼,它會自動改變儲存寫入到硬碟的字元編碼,如下圖所示。
image.png
很多人都知道在寫程式碼的時候,檔案最上方寫一行指定字元編碼的檔案頭:

# coding:utf-8
複製程式碼

但是可能並不知道原因,在Pycharm中,只要你這樣寫了就不會發生任何的字元編碼問題,但是如果換一個其他的IDE工具,這一行程式碼代表的是讀檔案所使用的字元編碼,如果這個IDE工具預設儲存寫入到硬碟的字元編碼是“GBK”,而且他不會隨著你的檔案頭而改變,那麼它儲存的時候就是以GBK儲存的,而讀的時候指定了UTF-8的字元編碼,計算機就會讀不出來,換了人來解決這個問題,如果不清楚它的成因,也可能會很懵逼。好就好在大部分的文字編輯器預設用的字元編碼都是UTF-8,一般人們寫檔案頭一般也是指定UTF-8為讀取的標準。所以,大部分不懂字元編碼的人出現錯誤可能性也比較低。

2.直譯器執行檔案時字元編碼異同

Python中有一種資料型別會涉及到字元的概念,這種資料型別就是字串。我們在寫程式時候如果不指定字元編碼,儲存的時候預設就是UTF-8的字元編碼,而Python3直譯器預設也是使用UTF-8來讀取的,所以,它在Python3中執行是沒有任何問題的,但是Python2中就不行了,所以為了執行Python程式的前兩個階段不出現問題,我們統一的都會加上檔案頭指定UTF-8字元編碼,但是到了第三個階段,就會開始識別語法了,我們在Pycharm中寫入如下程式碼內容,計算機在執行的時候會先把這些程式碼以Unicode編碼讀入記憶體,然後Python直譯器檢測到程式碼中要儲存一個“上”這個字串變數,直譯器就會呼叫計算機申請記憶體空間,把“上”這個字元存入到計算機記憶體中,儲存的方式自然還是二進位制,但是應該用什麼字元編碼儲存呢?

# coding:gbk

x = '上'
複製程式碼

涉及到Python中的資料型別,這是龜叔寫的直譯器,自然是他說了算。

Python2中的字串分為兩種型別:1 str,2 unicode

在Python2中如果指定字元編碼,那麼字串的儲存會按照你指定的字元編碼來完成,正如上面的程式碼,我們使用GBK編碼來指定,那麼在記憶體中就會用兩個位元組來儲存一個漢字,接下來我們就來驗證一下,如果我們直接列印的這個x的話,從理論上講,x對應的就是一串二進位制數,而列印的時候Python2直譯器幫你做了一個轉化,目的是為了讓你能夠更加直觀的看到它的列印結果,但是會出現亂碼(這個亂碼問題我們最後再講),我們可以使用以下程式碼這種形式來進行列印,就可以看到還沒有轉化之前的結果(龜叔還沒來得及在Python2中的做轉化,就寫了Python3)。

# coding:gbk

# 直譯器已經切換到Python2

x = "上"
# print(x)  # Python2加括號也能列印
print([x, ])
"""
輸出:
['\xc9\xcf']
"""
複製程式碼

我們從輸出結果上來看,“\x”代表的是十六進位制,“c9”和“cf”分別代表兩個十六進位制位,一個十六進位制位對應四個二進位制位,那麼列印結果'\xc9\xcf'就是16個二進位制位,也就是16bit=2bytes,這也就證明了GBK編碼儲存中文用兩個位元組。接下來用同樣的方式我們再來驗證一下UTF-8儲存常見漢字用3個位元組,程式碼如下。

# coding:utf-8

# 直譯器已經切換到Python2

x = "上"
# print(x)  # Python2加括號也能列印
print([x, ])
"""
輸出:
['\xe4\xb8\x8a']
"""
複製程式碼

3. 字元編碼的轉換

通過前面的講解我們已經清楚了unicode編碼可以轉換成GBK或者UTF-8,相反也可以轉換,他們之間的轉換過程如下:

unicode ===>編碼encode===>GBK/UTF-8 GBK/UTF-8 ===>解碼decode===>unicode

所以,必然會有以下程式碼的執行:

# coding:utf-8

# 直譯器已經切換到Python2

x = "上"
# print(x.decode('gbk'))  # 使用utf-8編碼,使用gbk無法解碼
print(x.decode('utf-8'))  # 使用utf-8編碼,使用utf-8解碼
print([x.decode('utf-8'), ])  # 在列表列印出龜叔沒有轉換之前的unicode編碼
"""
輸出:
上
[u'\u4e0a']  # \u 代表unicode
"""
複製程式碼

我們來比較一下unicode字元編碼表中“上”這個字元,下圖是unicode字元編碼表中部分內容,左側4開頭的如“4E05”就是unicode的十六進位制表示形式,很明顯,通過對比,我們可以找到字元“上”對應unicode的十六進位制就是“4e0a”。

image.png

在unicode中你可以看到有6個像“上”一樣的字元,第一個指的是簡體中文,第二個指的是香港繁體字,第三個是臺灣繁體字,第四個是日本字,這些字元都是看起來類似的,所以在unicode中統一都用“4e0a”來儲存,但是每一個不同編碼的字元為了區分又新增了類似“494F”這樣的標識,unicode編碼也是通過這種方式來完成與萬國編碼的轉換過程。

4. Python2兩種字串型別的區別

# coding:gbk

# 直譯器已經切換到Python2

x = "上"
print(type(x))  # str型別
print([x, ])  # 以gbk編碼儲存
print([x.decode('gbk'), ])  # 解碼後就是unicode,與下面儲存的字元編碼一致

y = u'上'  # 定義字串的時候前面加"u"
print(type(y))  # unicode型別
print([y, ])  # 以unicode編碼儲存
複製程式碼

5. 字元編碼的儲存與取值原理

我們以GBK編碼為例,儲存一個字元“上”,那麼儲存的結果應該是與上圖unicode編碼中對應的GBK編碼“494F”相對應,但是,請看如下程式碼,列印結果並不對應,這又是為何呢?

# coding:gbk

# 直譯器已經切換到Python2

x = "上"
print([x, ])  # 以gbk編碼儲存
"""
輸出
['\xc9\xcf']
"""
複製程式碼

GBK可以儲存中文或者英文字元,假如我們要儲存一串字元“你a好”,應該是使用8bit+8bit+8bit+8bit+8bit一共40個位元位來儲存。這樣儲存的時候沒有問題,但是取值卻成了問題,計算機並不知道從那一個位元位開始到哪一個位元位結束是第一個字元,所以這樣連在一起無法取值(韓愈《師說》中寫到:“句讀之不知”也是一樣的道理,這句話指的是不理解標點符號,那麼自然不理解句子的開始和結束,也就無法讀懂一句話)。計算機在取值的時候也一定要有一個明確的開始和結束,所以,其實計算機在儲存的時候並不是8個位元位都用來表示字元的,這也是GBK表面上是儲存65535個漢字其實並沒有那麼多,它只能儲存3萬多個。GBK能表示兩種字元,分別是中文和英文,其實它的第一個字元是用來區分中文和英文的,所以要儲存一個“你a好”字串,應該是如下儲存方式:

(1+7bit)+(1+7bit)+(1+7bit)+(1+7bit)+(1+7bit)

假如第一個位元位是1代表中文字元,那麼接下來他就會先讀第一個位元組第一個位元位代表中文,接下來把這個位元組讀完了之後,需要再一次讀取第二個位元組的第一個位元位,剛好第一個位元位也是1,那麼他就把後面的7個位元位讀完了就能準確地讀出這個中文字元,同理,如果一個字元的第一個位元位是0,那麼它代表一個英文字元,那麼它只需要把這個位元組的內容讀完就能準確地讀出這個英文字元。

計算機原本都是機器,它之所以智慧都是源自於人類的智慧。

如果你使用GBK編碼儲存而是UTF-8編碼去讀取,由於兩種編碼每個字元所佔用的位元組數不同,那麼關於每個字元的第一個位元組的第一個位元位的標識也就不一致,就可能會產生第一個字元沒有讀完而後面的位元位標識與前面剛讀過的字元標識不一致,那麼每個字元都不能準確的讀出來,這就會產生亂碼。 既然已經清楚了它的存取原理那麼現在我們再來看一下GBK編碼儲存一箇中文字元“上”的過程,如下圖所示。

gbk.png
這個過程主要分為四個階段:

  1. 先“上”這個字元轉化十六進位制分別是“c”,“9”,“c”,“f”
  2. 把“c”,“9”,“c”,“f”分別轉化成二進位制對應的01010這些東西
  3. 取出每個位元組的第一個二進位制位
  4. 把剩餘的每個十六進位制位對應的多個二進位制位再次轉化成十六進位制

所以你看到的結果和unicode字元編碼表無法對應是由於計算機的存取原理所導致的。

6. 字元編碼總結

最後再回到第二小節直接列印x會出現亂碼的問題,龜叔在轉化的時候按照你在記憶體儲存的時候的字元編碼GBK來轉化,但是Pycharm預設使用的列印到螢幕的字元編碼是UTF-8(這個可以改,但是不建議你修改),所以直接在Pycharm列印x你會看到亂碼,如果是Windows系統的使用者,可以在Windows終端以Python2執行程式碼,他就不會出現亂碼,因為Windows平臺預設列印到終端的編碼也是GBK,如果是MacOS系統的使用者,在終端以Python2執行程式碼還是會出現亂碼,因為MacOS系統預設列印到到終端的編碼是和Pycharm一樣的UTF-8。

所以很多寫Python2程式的人都會在str前面加一個“u”(可能他們自己也不知道這是為什麼),這就是希望能夠把所有的字串按照unicode字元編碼來儲存,這樣可以和任意編碼轉換。 有的人可能會有疑問,Python為什麼要來兩種字串型別,這不是給使用者徒增麻煩嗎?

你能想到的龜叔自然也能想到,這裡有一點關於時間先後的問題。

Python語言寫於1989年,1991年Python2才正式誕生,unicode是1990年開始研發,1994年才真正誕生,UTF-8的誕生就更加的晚了,所以最開始的Python直譯器一定是使用ASCII編碼,那時候還沒有unicode字元編碼。

我們花費了大量的篇幅講解了字元編碼,這裡面有一定的理論知識,但需要你記住的結論非常少,其他的深入的東西沒有人會問你(詳細知道的也沒幾個人),在Python3中所有的字串都是用unicode編碼來儲存(不需要前面加“u”),字串的資料型別也只有一個,就是str,只要是用unicode來儲存的,那麼所有的字串在任何情況下都不會出現亂碼,在Python3中程式碼示例如下:

# coding:gbk

# 直譯器已經切換到Python3

x = "上"
print(x)
# unicode===>編碼encode===>gbk
code_gbk = x.encode('gbk')
code_utf8 = x.encode('utf-8')

print(code_gbk)
print(code_utf8)
print(type(code_gbk))
print(type(code_utf8))

print(code_gbk.decode('gbk'))
print(code_utf8.decode('utf-8'))

"""
輸出:
上
b'\xc9\xcf'
b'\xe4\xb8\x8a'
<class 'bytes'>
<class 'bytes'>
上
上
"""
複製程式碼

從Python3中列印x.encode('gbk') 的結果中你可以看到是:‘\xc9\xcf’,這正是Python2中的str型別的值,而在Python3是bytes型別,在Python2中則是str型別,他們資料型別雖然不一致,但是儲存的結果確是一致的,他們他們之間必然存在一種關聯就是:Python2中的str型別就是Python3的bytes型別,我們可以檢視Python2的str型別的原始碼,看到部分程式碼如下圖所示:

image.png
編碼之後的結果資料型別是bytes,看起來像是位元組,其實是十六進位制,計算機會自動把十六進位制轉化成二進位制,你可以把bytes型別等同於二進位制去看待,網路傳輸也是基於二進位制來傳輸的,你在上網的過程中網速很慢的時候可以看到1b/s,這就是指的每秒傳輸一個位元組。

相關文章