一、計算機基礎
二、文本編輯器存取文件的原理
- 打開編輯器就打開了啟動了一個進程,是在內存中的,所以,用編輯器編寫的內容也都是存放與內存中的,斷電后數據丟失。
- 要想永久保存,需要點擊保存按鈕:編輯器把內存的數據刷到了硬盤上。
- 在我們編寫一個py文件(沒有執行),跟編寫其他文件沒有任何區別,都只是在編寫一堆字符而已。
三、Python解釋器執行py文件的原理
- 第一階段:Python解釋器啟動,此時就相當於啟動了一個文本編輯器
- 第二階段:Python解釋器相當於文本編輯器,去打開test.py文件,從硬盤上將test.py的文件內容讀入到內存中(小復習:pyhon的解釋性,決定了解釋器只關心文件內容,不關心文件后綴名)。
- 第三階段:Python解釋器解釋執行剛剛加載到內存中test.py的代碼( ps:在該階段,即真正執行代碼時,才會識別Python的語法,執行文件內代碼,當執行到name="egon"時,會開辟內存空間存放字符串"egon")。
四、Python解釋器與文件本編輯的異同
- 相同點:Python解釋器是解釋執行文件內容的,因而Python解釋器具備讀py文件的功能,這一點與文本編輯器一樣。
- 不同點:文本編輯器將文件內容讀入內存后,是為了顯示或者編輯,根本不去理會Python的語法,而Python解釋器將文件內容讀入內存后,可不是為了給你瞅一眼Python代碼寫的啥,而是為了執行Python代碼、會識別Python語法。
五、字符編碼介紹
5.1 什么是字符編碼
計算機要想工作必須通電,即用‘電’驅使計算機干活,也就是說‘電’的特性決定了計算機的特性。電的特性即高低電平(人類從邏輯上將二進制數1對應高電平,二進制數0對應低電平),關於磁盤的磁特性也是同樣的道理。結論:計算機只認識數字。
很明顯,我們平時在使用計算機時,用的都是人類能讀懂的字符(用高級語言編程的結果也無非是在文件內寫了一堆字符),如何能讓計算機讀懂人類的字符?
必須經過一個過程:
- 字符 --------》翻譯過程 -------》數字
總而言之,字符編碼是將人類的字符編碼成計算機能識別的數字,這種轉換必須遵循一套固定的標准,該標准無非是人類字符與數字的對應關系,稱之為字符編碼表。
5.2 涉及到字符編碼的兩個場景
- 一個Python文件中的內容是由一堆字符組成的,存取均涉及到字符編碼問題(Python文件並未執行,前兩個階段均屬於該范疇)。
- Python中的數據類型字符串是由一串字符組成的(Python文件執行時,即第三個階段)。
5.3 字符編碼發展史與分類
計算機由美國人發明,最早的字符編碼為ASCII,只規定了英文字母數字和一些特殊字符與數字的對應關系。最多只能用 8 位來表示(一個字節),即:2**8 = 256,所以,ASCII碼最多只能表示 256 個符號。
當然我們編程語言都用英文沒問題,ASCII夠用,但是在處理數據時,不同的國家有不同的語言,中國人會加入中文,日本人會在自己的程序中加入日文,韓國人也是。
但是要表示中文,單拿一個字節表表示一個漢子,是不可能表達完的(連小學生都認識兩千多個漢字),解決方法只有一個,就是一個字節用>8位2進制代表,位數越多,代表的變化就多,這樣,就可以盡可能多的表達出不通的漢字。
所以中國人規定了自己的標准gb2312編碼,規定了包含中文在內的字符與數字的對應關系。
日本人規定了自己的Shift_JIS編碼;韓國人規定了自己的Euc-kr編碼(另外,韓國人說,計算機是他們發明的,要求世界統一用韓國編碼,但世界人民沒有搭理他們)。
這時候問題出現了,精通18國語言的小周同學謙虛的用8國語言寫了一篇文檔,那么這篇文檔,按照哪國的標准,都會出現亂碼(因為此刻的各種標准都只是規定了自己國家的文字在內的字符跟數字的對應關系,如果單純采用一種國家的編碼格式,那么其余國家語言的文字在解析時就會出現亂碼)。所以迫切需要一個世界的標准(能包含全世界的語言)於是Unicode應運而生(韓國人表示不服,然后沒有什么卵用)。
ascii用1個字節(8位二進制)代表一個字符;Unicode常用2個字節(16位二進制)代表一個字符,生僻字需要用4個字節。
例:字母x,用ascii表示是十進制的120,二進制0111 1000。
漢字中已經超出了ASCII編碼的范圍,用Unicode編碼是十進制的20013,二進制的01001110 00101101。
字母x,用Unicode表示二進制0000 0000 0111 1000,所以Unicode兼容ascii,也兼容萬國,是世界的標准。
這時候亂碼問題消失了,所有的文檔我們都使用但是新問題出現了,如果我們的文檔通篇都是英文,你用Unicode會比ascii耗費多一倍的空間,在存儲和傳輸上十分的低效。
本着節約的精神,又出現了把Unicode編碼轉化為“可變長編碼”的UTF-8(Unicode Transformation Format-8)編碼。UTF-8編碼把一個Unicode字符根據不同的數字大小編碼成1-6個字節,常用的英文字母被編碼成1個字節,漢字通常是3個字節,只有很生僻的字符才會被編碼成4-6個字節。如果你要傳輸的文本包含大量英文字符,用UTF-8編碼就能節省空間:
字符 | ASCII | Unicode | UTF-8 |
---|---|---|---|
A | 01000001 | 00000000 01000001 | 01000001 |
中 | x | 01001110 00101101 | 11100100 10111000 10101101 |
從上面的表格還可以發現,UTF-8編碼有一個額外的好處,就是ASCII編碼實際上可以被看成是UTF-8編碼的一部分,所以,大量只支持ASCII編碼的歷史遺留軟件可以在UTF-8編碼下繼續工作。
5.4 內存為什么不用UTF-8呢?
說了那么一大堆,那為什么內存用Unicode,而不直接使用UTF-8呢?這樣不就可以直接把代碼從內存直接丟入硬盤了嗎?出現這個問題的原因是硬盤中還躺了其他國家的代碼,各個國家的代碼的二進制還需要運行在計算機上使用,因此內存中必須使用Unicode的編碼,因為Unicode能和硬盤中其他國家的二進制中的代碼進行轉換,但是UTF-8只是簡化了代碼的存儲,它並不能與其他國家硬盤中的代碼進行關系轉換。總而言之只有Unicode編碼才能運行其他國家硬盤中的代碼,而UTF-8的代碼無法進行該操作。
內存中還使用Unicode編碼,是因為歷史遺留問題造成的,但是因為現在寫代碼使用的都是UTF-8代碼,所以以后內存中的代碼都將變成UTF-8代碼,並且以前遺留的各個國家的代碼都將被淘汰,所以未來內存中使用的編碼也將使用UTF-8編碼替代Unicode編碼。
5.5 字符編碼之文本編輯器操作
5.6 亂碼分析
首先明確概念
- 文件從內存刷到硬盤的操作簡稱存文件
- 文件從硬盤讀到內存的操作簡稱讀文件
亂碼的兩種情況:
- 亂碼一:存文件時就已經亂碼
存文件時,由於文件內有各個國家的文字,我們單以shiftjis去存,
本質上其他國家的文字由於在shiftjis中沒有找到對應關系而導致存儲失敗。但當我們硬要存的時候,編輯並不會報錯(難道你的編碼錯誤,編輯器這個軟件就跟着崩潰了嗎???),但毫無疑問,不能存而硬存,肯定是亂存了,即存文件階段就已經發生亂碼,而當我們用shiftjis打開文件時,日文可以正常顯示,而中文則亂碼了。
- 亂碼二:存文件時不亂碼而讀文件時亂碼
存文件時用utf-8編碼,保證兼容萬國,不會亂碼,而讀文件時選擇了錯誤的解碼方式,比如gbk,則在讀階段發生亂碼,讀階段發生亂碼是可以解決的,選對正確的解碼方式就ok了。
六、總結
-
保證不亂碼的核心法則就是,字符按照什么標准而編碼的,就要按照什么標准解碼,此處的標准指的就是字符編碼。
-
在內存中寫的所有字符,一視同仁,都是Unicode編碼,比如我們打開編輯器,輸入一個“你”,我們並不能說“你”就是一個漢字,此時它僅僅只是一個符號,該符號可能很多國家都在使用,根據我們使用的輸入法不同這個字的樣式可能也不太一樣。只有在我們往硬盤保存或者基於網絡傳輸時,才能確定”你“到底是一個漢字,還是一個日本字,這就是Unicode轉換成其他編碼格式的過程了。簡而言之,就是內存中固定使用的就是Uncidoe編碼,我們唯一能改變的就是存儲到硬盤時使用的編碼。
- Unicode----->encode(編碼)-------->gbk
- Unicode<--------decode(解碼)<----------gbk