讀寫檔案是最常見的IO操作。
讀寫檔案就是請求作業系統打開一個檔案對象(通常稱為檔案描述符),然後,通過作業系統提供的接口從這個檔案對象中讀取資料(讀檔案),或者把資料寫入這個檔案對象(寫檔案)。
要以讀檔案的模式打開一個檔案對象,使用Python内置的open()函數,傳入檔案名和标示符:
f = open('/Users/michael/test.txt', 'r') #标示符'r'表示讀,這樣,我們就成功地打開了一個檔案。
如果檔案不存在,open()函數就會抛出一個IOError的錯誤,
如果檔案打開成功,接下來,調用read()方法可以一次讀取檔案的全部内容,Python把内容讀到記憶體,用一個str對象表示:
f.read() 'Hello, world!'
最後一步是調用close()方法關閉檔案。檔案使用完畢後必須關閉,因為檔案對象會占用作業系統的資源,并且作業系統同一時間能打開的檔案數量也是有限的:
f.close()
由于檔案讀寫時都有可能産生IOError,一旦出錯,後面的f.close()就不會調用。是以,為了保證無論是否出錯都能正确地關閉檔案,我們可以使用try ... finally來實作:
try:
f = open('/path/to/file', 'r')
print(f.read())
finally:
if f:
f.close()
但是每次都這麼寫實在太繁瑣,是以,Python引入了with語句來自動幫我們調用close()方法:
with open('/path/to/file', 'r') as f:
print(f.read())
這和前面的try ... finally是一樣的,但是代碼更佳簡潔,并且不必調用f.close()方法。
調用read()會一次性讀取檔案的全部内容,如果檔案有10G,記憶體就爆了,是以,要保險起見,可以反複調用read(size)方法,每次最多讀取size個位元組的内容。另外,調用readline()可以每次讀取一行内容,如果傳回一個空字元串, 說明已經已經讀取到最後一行。調用readlines()一次讀取所有内容并按行傳回list,如果設定可選參數 sizehint, 則讀取指定長度的位元組, 并且将這些位元組按行分割。
如果檔案很小,read()一次性讀取最友善;如果不能确定檔案大小,反複調用read(size)比較保險;如果是配置檔案,調用readlines()最友善:
for line in f.readlines():
print(line.strip()) # 把末尾的'\n'删掉
要讀取二進制檔案,比如圖檔、視訊等等,用'rb'模式打開檔案即可:
要讀取非UTF-8編碼的文本檔案,需要給open()函數傳入encoding參數,例如,讀取GBK編碼的檔案:
f = open('/Users/michael/gbk.txt', 'r', encoding='gbk')
遇到有些編碼不規範的檔案,你可能會遇到UnicodeDecodeError,因為在文本檔案中可能夾雜了一些非法編碼的字元。遇到這種情況,open()函數還接收一個errors參數,表示如果遇到編碼錯誤後如何處理。最簡單的方式是直接忽略:
f = open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore')
寫檔案和讀檔案是一樣的,唯一差別是調用open()函數時,傳入辨別符'w'或者'wb'表示寫文本檔案或寫二進制檔案:
f = open('/Users/michael/test.txt', 'w')
f.write('Hello, world!')
f.close()
你可以反複調用write()來寫入檔案,
.write(string) 将 string 寫入到檔案中, 然後傳回寫入的字元數。如果要寫入一些不是字元串的東西, 那麼将需要先進行字元串轉換str() 。
務必要調用f.close()來關閉檔案。當我們寫檔案時,作業系統往往不會立刻把資料寫入磁盤,而是放到記憶體緩存起來,空閑的時候再慢慢寫入。隻有調用close()方法時,作業系統才保證把沒有寫入的資料全部寫入磁盤。忘記調用close()的後果是資料可能隻寫了一部分到磁盤,剩下的丢失了。
是以,還是用with語句來得保險:
with open('/Users/michael/test.txt', 'w') as f:
f.write('Hello, world!')
要寫入特定編碼的文本檔案,請給open()函數傳入encoding參數,将字元串自動轉換成指定編碼。
以'w'模式寫入檔案時,如果檔案已存在,會直接覆寫(相當于删掉後新寫入一個檔案)。如果希望追加到檔案末尾可以傳入'a'以追加(append)模式寫入。
tt=open("xxx",)
ww=open("ccc","r+")
while 1:
text=tt.resd()
if not text:
break
ww.write(text)
tt.close()
ww.close()
file-like Object 檔案對象
open() 将會傳回一個 file 對象
像open()函數傳回的這種有個read()方法的對象,在Python中統稱為file-like Object。除了file外,還可以是記憶體的位元組流,網絡流,自定義流等等。
file-like Object不要求從特定類繼承,隻要寫個read()方法就行。
StringIO就是在記憶體中建立的file-like Object,常用作臨時緩沖。
file 檔案對象常用的函數:
f.tell()傳回檔案目前位置。它是從檔案開頭開始算起的位元組數。
f.close() 關閉檔案。關閉後檔案不能再進行讀寫操作。
f.seek(offset[, whence])設定檔案目前位置,from_what 的值, 如果是 0 表示開頭, 如果是 1 表示目前位置, 2 表示檔案的結尾,from_what 值為預設為0,即檔案開頭
例如:
- seek(x,0) : 從起始位置即檔案首行首字元開始移動 x 個字元
- seek(x,1) : 表示從目前位置往後移動x個字元
- seek(-x,2):表示從檔案的結尾往前移動x個字元
f.flush()重新整理檔案内部緩沖,直接把内部緩沖區的資料立刻寫入檔案, 而不是被動的等待輸出緩沖區寫入。
f.fileno()傳回一個整型的檔案描述符(file descriptor FD 整型), 可以用在如os子產品的read方法等一些底層操作上。
f.isatty()如果檔案連接配接到一個終端裝置傳回 True,否則傳回 False。
f.next()傳回檔案下一行。
f.read([size])從檔案讀取指定的位元組數,如果未給定或為負則讀取所有。
f.readline([size])讀取整行,包括 "\n" 字元。
f.readlines([sizeint])讀取所有行并傳回清單,若給定sizeint>0,傳回總和大約為sizeint位元組的行, 實際讀取值可能比 sizeint 較大, 因為需要填充緩沖區。
f.truncate([size])從檔案的首行首字元開始截斷,截斷檔案為 size 個字元,無 size 表示從目前位置截斷;截斷之後後面的所有字元被删除,其中 Widnows 系統下的換行代表2個字元大小。
f.write(str)将字元串寫入檔案,傳回的是寫入的字元長度。
f.writelines(sequence)向檔案寫入一個序列字元串清單,如果需要換行則要自己加入每行的換行符。
不同模式打開檔案的完全清單:
模式 | 描述 |
r | 以隻讀方式打開檔案。檔案的指針将會放在檔案的開頭。這是預設模式。 |
rb | 以二進制格式打開一個檔案用于隻讀。檔案指針将會放在檔案的開頭。 |
r+ | 打開一個檔案用于讀寫。檔案指針将會放在檔案的開頭。 |
rb+ | 以二進制格式打開一個檔案用于讀寫。檔案指針将會放在檔案的開頭。 |
w | 打開一個檔案隻用于寫入。如果該檔案已存在則打開檔案,并從開頭開始編輯,即原有内容會被删除。如果該檔案不存在,建立新檔案。 |
wb | 以二進制格式打開一個檔案隻用于寫入。如果該檔案已存在則打開檔案,并從開頭開始編輯,即原有内容會被删除。如果該檔案不存在,建立新檔案。 |
w+ | 打開一個檔案用于讀寫。如果該檔案已存在則打開檔案,并從開頭開始編輯,即原有内容會被删除。如果該檔案不存在,建立新檔案。 |
wb+ | 以二進制格式打開一個檔案用于讀寫。如果該檔案已存在則打開檔案,并從開頭開始編輯,即原有内容會被删除。如果該檔案不存在,建立新檔案。 |
a | 打開一個檔案用于追加。如果該檔案已存在,檔案指針将會放在檔案的結尾。也就是說,新的内容将會被寫入到已有内容之後。如果該檔案不存在,建立新檔案進行寫入。 |
ab | 以二進制格式打開一個檔案用于追加。如果該檔案已存在,檔案指針将會放在檔案的結尾。也就是說,新的内容将會被寫入到已有内容之後。如果該檔案不存在,建立新檔案進行寫入。 |
a+ | 打開一個檔案用于讀寫。如果該檔案已存在,檔案指針将會放在檔案的結尾。檔案打開時會是追加模式。如果該檔案不存在,建立新檔案用于讀寫。 |
ab+ | 以二進制格式打開一個檔案用于追加。如果該檔案已存在,檔案指針将會放在檔案的結尾。如果該檔案不存在,建立新檔案用于讀寫。 |