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__()
- enter()方法被執行
- enter()方法返回的值 - 這個例子中是"Foo",賦值給變數'sample'
- 執行程式碼塊,列印變數"sample"的值為 "Foo"
- 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>