Python編程(三)字符編碼與文件處理
計算機要想工作必須通電,也就是說‘電’驅使計算機幹活,而‘電’的特性,就是高低電平(高低平即二進制數1,低電平即二進制數0),也就是說計算機只認識數字
編程的目的是讓計算機幹活,而編程的結果說白了只是一堆字符,也就是說我們編程最終要實現的是:一堆字符驅動計算機幹活
所以必須經過一個過程:
字符--------(翻譯過程)------->數字
這個過程實際就是一個字符如何對應一個特定數字的標準,這個標準稱之為字符編碼
字符編碼 :字符--》二進制數字的標準
階段一:
ASCII:一個Bytes代表一個字符(英文+符號)
1Bytes=8bit,8bit可以表示256個字符
最初只用了後7位,127個數字,預留一位
階段二:
中國制定GBK
2Bytes代表一個字符
階段三:
語言多,混合出現亂碼
產生Unicode,統一用2Bytes代表一個字符,2**16-1 65535個
對於英文來說,這種方式多了一倍的空間,浪費空間
於是產生 UTF-8,對英文只用1Bytes,對中午用3 bYtes
unicode: 所有都是2Bytes
正確使用字符編碼:
內存中默認都是unicode
文件村:內存刷到硬盤
文件讀:硬盤讀到內存
1.文件執行前:文件存的時候用什麽編碼,讀的時候要用相同的編碼
2.文件執行時:才有了字符串這個數據類型的概念
x=‘hello‘ python3的字符串默認是unicode
unicode類型可以encode不可 x.encode(‘gbk‘)python3中
須知:
unicode:簡單粗暴,所有字符都是2Bytes,優點是字符->數字的轉換速度快,缺點是占用空間大
utf-8:精準,對不同的字符用不同的長度表示,優點是節省空間,缺點是:字符->數字的轉換速度慢,因為每次都需要計算出字符需要多長的Bytes才能夠準確表示
所有程序,最終都要加載到內存,程序保存到硬盤不同的國家用不同的編碼格式,但是到內存中我們為了兼容萬國(計算機可以運行任何國家的程序原因在於此),統一且固定使用unicode,這就是為何內存固定用unicode的原因,你可能會說兼容萬國我可以用utf-8啊,可以,完全可以正常工作,之所以不用肯定是unicode比utf-8更高效啊(uicode固定用2個字節編碼,utf-8則需要計算),但是unicode更浪費空間,沒錯,這就是用空間換時間的一種做法,而存放到硬盤,或者網絡傳輸,都需要把unicode轉成utf-8,因為數據的傳輸,追求的是穩定,高效,數據量越小數據傳輸就越靠譜,於是都轉成utf-8格式的,而不是unicode。
- 內存中使用的編碼是unicode,用空間換時間(程序都需要加載到內存才能運行,因而內存應該是盡可能的保證快)
- 硬盤中或者網絡傳輸用utf-8,網絡I/O延遲或磁盤I/O延遲要遠大與utf-8的轉換延遲,而且I/O應該是盡可能地節省帶寬,保證數據傳輸的穩定性。
亂碼:
亂碼一:存文件時就已經亂碼
存文件時,由於文件內有各個國家的文字,我們單以shiftjis去存,
本質上其他國家的文字由於在shiftjis中沒有找到對應關系而導致存儲失敗,用open函數的write可以測試,f=open(‘a.txt‘,‘w‘,encodig=‘shift_jis‘)
f.write(‘你\nて\n‘) #‘你‘因為在shiftjis中沒有找到對應關系而無法保存成功,只存‘て\n
但當我們用文件編輯器去存的時候,編輯器會幫我們做轉換,保證中文也能用shiftjis存儲(硬存,必然亂碼),這就導致了,存文件階段就已經發生亂碼
此時當我們用shiftjis打開文件時,日文可以正常顯示,而中文則亂碼了
亂碼二:存文件時不亂碼而讀文件時亂碼
存文件時用utf-8編碼,保證兼容萬國,不會亂碼,而讀文件時選擇了錯誤的解碼方式,比如gbk,則在讀階段發生亂碼,讀階段發生亂碼是可以解決的,選對正確的解碼方式就ok了,而存文件時亂碼,則是一種數據的損壞。
總結:
無論是何種編輯器,要防止文件出現亂碼(請一定註意,存放一段代碼的文件也僅僅只是一個普通文件而已,此處指的是文件沒有執行前,我們打開文件時出現的亂碼)
核心法則就是,文件以什麽編碼保存的,就以什麽編碼方式打開
文件處理:
打開文件時,需要指定文件路徑和以何等方式打開文件,打開後,即可獲取該文件句柄,日後通過此文件句柄對該文件操作。
打開文件的模式有:
- r ,只讀模式【默認模式,文件必須存在,不存在則拋出異常】
- w,只寫模式【不可讀;不存在則創建;存在則清空內容】
- x, 只寫模式【不可讀;不存在則創建,存在則報錯】
- a, 追加模式【可讀; 不存在則創建;存在則只追加內容】
"+" 表示可以同時讀寫某個文件
- r+, 讀寫【可讀,可寫】
- w+,寫讀【可讀,可寫】
- x+ ,寫讀【可讀,可寫】
- a+, 寫讀【可讀,可寫】
"b"表示以字節的方式操作
- rb 或 r+b
- wb 或 w+b
- xb 或 w+b
- ab 或 a+b
註:以b方式打開時,讀取到的內容是字節類型,寫入時也需要提供字節類型,不能指定編碼
flush原理:
- 文件操作是通過軟件將文件從硬盤讀到內存
- 寫入文件的操作也都是存入內存緩沖區buffer(內存速度快於硬盤,如果寫入文件的數據都從內存刷到硬盤,內存與硬盤的速度延遲會被無限放大,效率變低,所以要刷到硬盤的數據我們統一往內存的一小塊空間即buffer中放,一段時間後操作系統會將buffer中數據一次性刷到硬盤)
- flush即,強制將寫入的數據刷到硬盤
1. open()語法
open(file[, mode[, buffering[, encoding[, errors[, newline[, closefd=True]]]]]])
open函數有很多的參數,常用的是file,mode和encoding
file文件位置,需要加引號
mode文件打開模式,見下面3
buffering的可取值有0,1,>1三個,0代表buffer關閉(只適用於二進制模式),1代表line buffer(只適用於文本模式),>1表示初始化的buffer大小;
encoding表示的是返回的數據采用何種編碼,一般采用utf8或者gbk;
errors的取值一般有strict,ignore,當取strict的時候,字符編碼出現問題的時候,會報錯,當取ignore的時候,編碼出現問題,程序會忽略而過,繼續執行下面的程序。
newline可以取的值有None, \n, \r, ”, ‘\r\n‘,用於區分換行符,但是這個參數只對文本模式有效;
closefd的取值,是與傳入的文件參數有關,默認情況下為True,傳入的file參數為文件的文件名,取值為False的時候,file只能是文件描述符,什麽是文件描述符,就是一個非負整數,在Unix內核的系統中,打開一個文件,便會返回一個文件描述符。
2. Python中file()與open()區別
兩者都能夠打開文件,對文件進行操作,也具有相似的用法和參數,但是,這兩種文件打開方式有本質的區別,file為文件類,用file()來打開文件,相當於這是在構造文件類,而用open()打開文件,是用python的內建函數來操作,建議使用open
3. 參數mode的基本取值
Character | Meaning |
‘r‘ | open for reading (default) |
‘w‘ | open for writing, truncating the file first |
‘a‘ | open for writing, appending to the end of the file if it exists |
‘b‘ | binary mode |
‘t‘ | text mode (default) |
‘+‘ | open a disk file for updating (reading and writing) |
‘U‘ | universal newline mode (for backwards compatibility; should not be used in new code) |
r、w、a為打開文件的基本模式,對應著只讀、只寫、追加模式;
b、t、+、U這四個字符,與以上的文件打開模式組合使用,二進制模式,文本模式,讀寫模式、通用換行符,根據實際情況組合使用、
常見的mode取值組合
1 r或rt 默認模式,文本模式讀
2 rb 二進制文件
3
4 w或wt 文本模式寫,打開前文件存儲被清空
5 wb 二進制寫,文件存儲同樣被清空
6
7 a 追加模式,只能寫在文件末尾
8 a+ 可讀寫模式,寫只能寫在文件末尾
9
10 w+ 可讀寫,與a+的區別是要清空文件內容
11 r+ 可讀寫,與a+的區別是可以寫到文件任何位置
回到頂部
2.7 上下文管理
with open(‘a.txt‘,‘w‘) as f:
pass
with open(‘a.txt‘,‘r‘) as read_f,open(‘b.txt‘,‘w‘) as write_f:
data=read_f.read()
write_f.write(data)
回到頂部
2.8 文件的修改
import os
with open(‘a.txt‘,‘r‘,encoding=‘utf-8‘) as read_f, open(‘.a.txt.swap‘,‘w‘,encoding=‘utf-8‘) as write_f:
for line in read_f:
if line.startswith(‘hello‘):
line=‘哈哈哈\n‘
write_f.write(line)
os.remove(‘a.txt‘)
os.rename(‘.a.txt.swap‘,‘a.txt‘)
Python編程(三)字符編碼與文件處理