1. 程式人生 > >Lesson 024 —— python 檔案操作

Lesson 024 —— python 檔案操作

Lesson 024 —— python 檔案操作

open() 方法

Python open() 方法用於開啟一個檔案,並返回檔案物件,在對檔案進行處理過程都需要使用到這個函式,如果該檔案無法被開啟,會丟擲 OSError。

注意:使用 open() 方法一定要保證關閉檔案物件,即呼叫 close() 方法。

open() 函式常用形式是接收兩個引數:檔名(file)和模式(mode)。

open(file, mode='r')

完整的語法格式為:

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

引數說明:

  • file: 必需,檔案路徑(相對或者絕對路徑)。
  • mode: 可選,檔案開啟模式
  • buffering: 設定緩衝
  • encoding: 一般使用utf8.使用 b 模式開啟,不能指定 encoding 編碼。使用 t 模式,相當於使用 b 模式開啟然後進行編碼(使用 decode 進行解碼)翻譯。
  • errors: 報錯級別
  • newline: 區分換行符。newline=‘ ’表示不進行轉換(即\r\n 轉換為 \n)。
  • closefd: 傳入的file引數型別
  • opener:

mode 引數

模式 描述
t 文字模式 (預設)。
x 寫模式,新建一個檔案,如果該檔案已存在則會報錯。
b 二進位制模式。
+ 開啟一個檔案進行更新(可讀可寫)。
U 通用換行模式(不推薦)。
r 以只讀方式開啟檔案。檔案的指標將會放在檔案的開頭。這是預設模式。
rb 以二進位制格式開啟一個檔案用於只讀。檔案指標將會放在檔案的開頭。這是預設模式。一般用於非文字檔案如圖片等。
r+ 開啟一個檔案用於讀寫。檔案指標將會放在檔案的開頭。
rb+ 以二進位制格式開啟一個檔案用於讀寫。檔案指標將會放在檔案的開頭。一般用於非文字檔案如圖片等。
w 開啟一個檔案只用於寫入。如果該檔案已存在則開啟檔案,並從開頭開始編輯,即原有內容會被刪除。如果該檔案不存在,建立新檔案。
wb 以二進位制格式開啟一個檔案只用於寫入。如果該檔案已存在則開啟檔案,並從開頭開始編輯,即原有內容會被刪除。如果該檔案不存在,建立新檔案。一般用於非文字檔案如圖片等。
w+ 開啟一個檔案用於讀寫。如果該檔案已存在則開啟檔案,並從開頭開始編輯,即原有內容會被刪除。如果該檔案不存在,建立新檔案。
wb+ 以二進位制格式開啟一個檔案用於讀寫。如果該檔案已存在則開啟檔案,並從開頭開始編輯,即原有內容會被刪除。如果該檔案不存在,建立新檔案。一般用於非文字檔案如圖片等。
a 開啟一個檔案用於追加。如果該檔案已存在,檔案指標將會放在檔案的結尾。也就是說,新的內容將會被寫入到已有內容之後。如果該檔案不存在,建立新檔案進行寫入。
ab 以二進位制格式開啟一個檔案用於追加。如果該檔案已存在,檔案指標將會放在檔案的結尾。也就是說,新的內容將會被寫入到已有內容之後。如果該檔案不存在,建立新檔案進行寫入。
a+ 開啟一個檔案用於讀寫。如果該檔案已存在,檔案指標將會放在檔案的結尾。檔案開啟時會是追加模式。如果該檔案不存在,建立新檔案用於讀寫。
ab+ 以二進位制格式開啟一個檔案用於追加。如果該檔案已存在,檔案指標將會放在檔案的結尾。如果該檔案不存在,建立新檔案用於讀寫。

預設為文字模式,如果要以二進位制模式開啟,加上 b

file 物件

只要不是 read() 方法,其餘的方法移動游標都是按位元組計算。read() 方法按照字元計算。seek() 按位元組調整游標,若要使用 seek() 其他模式(預設從頭開始),使用二進位制模式讀入檔案。

file 物件使用 open 函式來建立,下表列出了 file 物件常用的函式:

序號 方法及描述 描述
1 file.close() 關閉檔案。關閉後文件不能再進行讀寫操作。
2 file.flush() 重新整理檔案內部緩衝,直接把內部緩衝區的資料立刻寫入檔案, 而不是被動的等待輸出緩衝區寫入。
3 file.fileno() 返回一個整型的檔案描述符(file descriptor FD 整型), 可以用在如os模組的read方法等一些底層操作上。
4 file.isatty() 如果檔案連線到一個終端裝置返回 True,否則返回 False。
5 file.next() 返回檔案下一行。
6 file.read([size]) 從檔案讀取指定的位元組數,如果未給定或為負則讀取所有。
7 file.readline([size]) 讀取整行,包括 "\n" 字元。
8 file.readlines([sizeint]) 讀取所有行並返回列表,若給定sizeint>0,返回總和大約為sizeint位元組的行, 實際讀取值可能比 sizeint 較大, 因為需要填充緩衝區。
9 file.seek(offset[, whence]) 設定檔案當前位置。offset:開始的偏移量,也就是代表需要移動偏移的位元組數。whence:可選,預設值為 0。給offset引數一個定義,表示要從哪個位置開始偏移;0代表從檔案開頭開始算起,1代表從當前位置開始算起,2代表從檔案末尾算起。
10 file.tell() 返回檔案當前位置,即檔案指標當前位置。
11 file.truncate([size])] 從檔案的首行首字元開始截斷,截斷檔案為 size 個字元,無 size 表示從當前位置截斷;截斷之後後面的所有字元被刪除,其中 Widnows 系統下的換行代表2個字元大小。
12 file.write(str) 將字串寫入檔案,返回的是寫入的字元長度。
13 file.writelines(sequence) 向檔案寫入一個序列字串列表,如果需要換行則要自己加入每行的換行符。

檔案物件屬性

編號 屬性 描述
1 file.closed 如果檔案關閉則返回true,否則返回false
2 file.mode 返回開啟檔案的訪問模式。
3 file.name 返回檔案的名稱。

使用 with 操作檔案

獲取一個檔案控制代碼,從檔案中讀取資料,然後關閉檔案控制代碼。
如果不用with語句,程式碼如下:

file = open("/tmp/foo.txt")
data = file.read()
file.close()

這裡有兩個問題。一是可能忘記關閉檔案控制代碼;二是檔案讀取資料發生異常,沒有進行任何處理。下面是處理異常的加強版本:

file = open("/tmp/foo.txt")
try:
    data = file.read()
finally:
    file.close()

雖然這段程式碼執行良好,但是太冗長了。這時候就是with一展身手的時候了。除了有更優雅的語法,with還可以很好的處理上下文環境產生的異常。下面是with版本的程式碼:

with open("/tmp/foo.txt") as file:
    data = file.read()

這看起來充滿魔法,但不僅僅是魔法,Python對with的處理還很聰明。基本思想是with所求值的物件必須有一個__enter__()方法,一個__exit__()方法。緊跟with後面的語句被求值後,返回物件的__enter__()方法被呼叫,這個方法的返回值將被賦值給as後面的變數。當with後面的程式碼塊全部被執行完之後,將呼叫前面返回物件的__exit__()方法。

class Sample:
    def __enter__(self):
        print("In __enter__()")
        return "Foo"
 
    def __exit__(self, type, value, trace):
        print("In __exit__()")
 
def get_sample():
    return Sample()
 
with get_sample() as sample:
    print("sample:", sample)
    
# 結果
In __enter__()
sample: Foo
In __exit__()
  1. enter()方法被執行
  2. enter()方法返回的值 - 這個例子中是"Foo",賦值給變數'sample'
  3. 執行程式碼塊,列印變數"sample"的值為 "Foo"
  4. exit()方法被呼叫

with真正強大之處是它可以處理異常。可能你已經注意到Sample類的__exit__方法有三個引數- val, type 和 trace。 這些引數在異常處理中相當有用。實際上,在with後面的程式碼塊丟擲任何異常時,exit()方法被執行。正如例子所示,異常丟擲時,與之關聯的type,value和stack trace傳給__exit__()方法,因此丟擲的ZeroDivisionError異常被打印出來了。開發庫時,清理資源,關閉檔案等等操作,都可以放在__exit__方法當中。

開啟大檔案

with語句開啟和關閉檔案,包括丟擲一個內部塊異常。for line in f檔案物件f視為一個迭代器,會自動的採用緩衝IO和記憶體管理,防止記憶體溢位。

#If the file is line based
with open(...) as f:
  for line in f:
    process(line) # <do something with line>