如何使用 open 函式開啟檔案?以及編碼,解碼,換行,緩沖等問題
訂閱 480
本節所講述的是如何在 Python 中開啟檔案,至於檔案的讀取和寫入,請參考如何使用 Python 檔案物件讀取及寫入檔案?以及檔案指標,關閉檔案,取得檔案物件資訊等問題一節。本節的「換行₁」一詞是指產生新的一行,類似於在編輯器中按下Enter鍵。
使用 open 函式開啟檔案
通過 Python 的內建函式open,你可以快速的開啟某個檔案,這不像其他的一些程式設計語言,比如 C#,需要預先匯入特定的模組或命名空間。當然,open函式的作用是開啟檔案而不是存取檔案中的內容,你需要呼叫其傳回的檔案物件(file object)的相關方法來完成內容的讀取或寫入。
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
- file 參數
file參數是一個表示檔案路徑的字串,或類路徑(path-like)物件,或整合檔案的 Python 檔案描述器(file descriptor)。如果該參數是檔案路徑,那麽closefd參數必須是True,否則將引發例外狀況ValueError: Cannot use closefd=False with file name。Python 檔案描述器可通過
os模組的open函式建立,但請區別於內建函式open,他們並不相同。- mode 參數
mode參數是一個字串,用於指示檔案的開啟模式,比如r(讀取)。該參數的具體用法,請參考指定檔案開啟模式一段。- buffering 參數
buffering參數是一個整數,用於表示緩沖策略。該參數的具體用法,請參考指定緩沖策略一段。- encoding 參數
encoding參數是一個字串,用於表示被開啟的文字檔案的編碼格式。該參數的具體用法,請參考指定檔案的編碼格式一段。- errors 參數
errors參數是一個字串,用於表示如何處理解碼和編碼錯誤。該參數的具體用法,請參考指定編碼和解碼錯誤的處理方式一段。- newline 參數
newline參數是一個字串,用於表示處理換行₁的方式。該參數的具體用法,請參考指定換行₁的處理方式一段。- closefd 參數
closefd參數是一個布林值(預設值為True),用於設定當檔案關閉時是否同時關閉file參數對應的檔案描述器,如果為False,那麽不會關閉檔案描述器,這意味著你可以使用檔案描述器再次開啟檔案。當file參數是檔案的路徑時,closefd參數必須保持預設值True,否則將導致例外狀況ValueError: Cannot use closefd=False with file name。- opener 參數
opener參數是一個傳回檔案描述器的函式或方法,傳回的檔案描述器將用於開啟檔案。該參數的具體用法,請參考自訂檔案描述器的建立方式一段。
在下面的範例中,我們通過os模組的open函式(不是內建函式open)建立了一個檔案描述器,並使用該檔案描述器開啟了檔案,由於closefd參數為False,因此當檔案被關閉之後,你依然可以通過檔案描述器再次開啟檔案。
需要指出的是,使用檔案描述器是沒有必要的,一般情況下,應直接呼叫函式open來開啟檔案。
# 請將命令列跳躍至腳本檔案 open_fd.py 所在的目錄,然後執行他
# 使用 os 模組的 open 函式建立檔案描述器
import os
fd = os.open('info.txt', os.O_RDONLY)
# 使用檔案描述器開啟檔案
file = open(fd, encoding='utf8', closefd=False)
print(file.read())
# 不會同時關閉檔案描述器
file.close()
# 可以使用檔案描述器再次開啟檔案
open(fd, encoding='utf8')今天天氣不錯今天天氣不錯指定檔案開啟模式
open函式的mode參數可用於設定檔案的開啟模式,並影響接下來的檔案操作,比如,當檔案以唯讀模式開啟時,你將無法對檔案進行寫入。mode參數是一個字串,他可以是以下值之一,或他們的某種組合。
模式 作用 r 預設值,表示可讀取檔案中的內容 w 清空檔案中的內容,並可將新內容寫入檔案 a 可將內容寫入檔案,預設追加至檔案末尾 x 建立新檔案,並可將內容寫入其中 t 預設值,作為文字檔案開啟 b 作為二進位檔案開啟 + 額外允許讀取或寫入檔案
一般情況下,r,w,a,x中的一個需要存在於open函式的mode參數中,否則例外狀況ValueError: Must have exactly one of create/read/write/append mode and at most one plus將被擲回,並且r,w,a,x不能同時出現,比如,rw或ra這樣的模式是無效的,例外狀況ValueError: must have exactly one of create/read/write/append mode將被擲回。
由於r,w,a,x不能同時出現,如果希望open函式所開啟的檔案同時支援讀取和寫入操作,那麽應在mode參數中增加+,比如,r+,w+。
此外,一些模式組合是明顯無效的,比如,rtb是無效的,因為無法將一個檔案同時作為文字檔案和二進位檔案開啟。
Python 3.11 版本移除了U模式。
# 請將命令列跳躍至腳本檔案 mode.py 所在的目錄,然後執行他
# 可以對檔案進行讀取及寫入,若檔案不存在則引發例外狀況
file = open('info.txt', 'r+', encoding='utf8')
# 讀取檔案中的行
print(file.readlines())
# 寫入新的行
file.writelines(['\n這是新的一行'])
# 需要 r,w,a,x 中的一個
try: open('info.txt', 't', encoding='utf8')
except ValueError as e: print(e)
# r,w,a,x 不能同時出現
try: open('info.txt', 'rw', encoding='utf8')
except ValueError as e: print(e)['今天天氣不錯']
Must have exactly one of create/read/write/append mode and at most one plus
must have exactly one of create/read/write/append modeopen 函式如何處理檔案不存在的情況?
當你選擇r,w和a中的某一個作為mode參數時,open函式將采用不同的方式來處理檔案不存在的情況。
對於r模式,如果需要開啟的檔案不存在,那麽open函式將擲回例外狀況FileNotFoundError: [Errno …] No such file or directory: '…'。對於w和a模式,如果需要開啟的檔案不存在,那麽open函式將立刻建立該檔案。
與以上提到的三種模式不同,x模式並不處理檔案不存在的情況,相反的,如果被開啟的檔案已經存在,那麽open函式將擲回例外狀況FileExistsError: [Errno …] File exists: '…'。
在下面的範例中,使用a模式開啟檔案no.md,將導致該檔案被自動建立。
# 請將命令列跳躍至腳本檔案 file_exists.py 所在的目錄,然後執行他
# 使用 r 模式開啟不存在的檔案 no.md
try: open('no.md', 'r')
except FileNotFoundError as e: print(e)
# 使用 a 模式將自動建立不存在的檔案 no.md
open('no.md', 'a')
# 使用 x 模式開啟已經存在的檔案 no.md
try: open('no.md', 'x')
except FileExistsError as e: print(e)# r 模式
[Errno 2] No such file or directory: 'no.md'
# x 模式
[Errno 17] File exists: 'no.md'無論是否寫入新內容,open 函式都將在 w 模式下清空檔案中的內容
如果選擇w作為檔案的開啟模式,那麽open函式將清空被開啟檔案中的內容,即便接下來你並沒有使用該函式傳回的檔案物件,將新的內容寫入檔案。
在下面的範例中,雖然沒有通過檔案物件向檔案寫入資料,但檔案中的內容將被清空。
# 請將命令列跳躍至腳本檔案 w_clear.py 所在的目錄,然後執行他
# 檔案 data.txt 中的內容將被清空
open('data.txt', 'w')一些資料開啟二進位檔案時不需要指定編碼格式
對於b模式,你不需要為open函式指定檔案的編碼格式(即encoding參數),否則將引發例外狀況ValueError: binary mode doesn't take an encoding argument。
指定緩沖策略
通過open函式的buffering參數,可以為open函式傳回的檔案物件指定緩沖策略,在緩沖策略的作用下,Python 檔案物件會從緩沖區讀取資料或將資料寫入緩沖區,而不是直接針對檔案進行讀取和寫入,這樣做的目的是為了減少儲存裝置的存取次數,提高程式碼的執行效率。
對於二進位檔案,open函式的buffering參數可以是0(如果是文字檔案,buffering參數為0將導致例外狀況ValueError: can't have unbuffered text I/O),這表示不進行緩沖,通過檔案物件寫入的資料將直接儲存至二進位檔案,如果buffering參數的值大於1,那麽buffering參數表示緩沖區的大小。
如果buffering參數為預設值-1,那麽非互動文字檔案和二進位檔案將采用由運算式io.DEFAULT_BUFFER_SIZE所指定的大小來建立緩沖區,互動文字檔案(檔案物件的isatty方法傳回True)則采用行緩沖策略。
# 請將命令列跳躍至腳本檔案 buffer.py 所在的目錄,然後執行他
# 設定緩沖區的大小為 2
file = open('buffer_b.txt', 'wb', 2)
# b'1' 將被存放在緩沖區
file.write(b'1')
# b'2' 將被存放在緩沖區
file.write(b'2')
# b'12' 會被立即儲存至檔案,b'3' 將被存放在緩沖區
file.write(b'3')
# b'34567' 會被立即儲存至檔案
file.write(b'4567')如何指定文字檔案采用行緩沖策略?
對於文字檔案,如果open函式的buffering參數為1,那麽將采用行緩沖策略,無論open函式的newline參數指定了哪種換行₁方式,當通過檔案物件寫入\n,\r\n或\r時,都將使緩沖區中的資料被儲存至檔案。
這裏需要說明的是,你必須明確的通過檔案物件將\n,\r\n或\r寫入,呼叫檔案物件的writelines方法並不能觸發行緩沖策略,如果被寫入的字串不包含\n,\r\n,\r。
在下面的範例中,呼叫方法writelines之後,abc被存放在緩沖區,因為沒有出現\n,\r\n或\r。
# 請將命令列跳躍至腳本檔案 buffer_line.py 所在的目錄,然後執行他
# 啟用行緩沖策略
file = open('buffer_line.txt', 'w', 1, encoding='utf8', newline='')
# abc 不會被立即儲存至檔案
file.writelines(['a', 'b', 'c'])
# abcd\r 會被立即儲存至檔案
file.write('d\r')
# e\n 會被立即儲存至檔案
file.write('e\n')
# f\r\n 會被立即儲存至檔案
file.write('f\r\n')指定檔案的編碼格式
當通過open函式開啟文字檔案時,你應該給出文字檔案的編碼,即open函式的encoding參數。當然,如果encoding參數被忽略或被設定為空值None,那麽open函式將采用locale模組的getencoding方法所傳回的編碼格式,即本機預設的編碼格式。
雖然 Python 支援大部分的檔案編碼格式,比如常見的utf8,但這並不意味著所有的編碼格式都能夠被 Python 處理。
# 請將命令列跳躍至腳本檔案 encoding.py 所在的目錄,然後執行他
# 使用編碼格式 utf-8 開啟檔案 utf8.txt
file = open('utf8.txt', 'r', encoding='utf8')
print(file.read())這是編碼格式為 utf-8 的檔案這是編碼格式為 utf-8 的檔案open 函式支援編碼格式的別名並且不區分名稱的大小寫
對於某種編碼格式,Python 可能為其定義了別名,以方便開發人員書寫程式碼,比如,utf8,utf-8和utf_8在執行結果上是相同的。此外,open函式也不區分編碼格式的名稱的大小寫,書寫utf8,Utf8或UTF8在執行結果上是相同的。
你可以匯入encodings模組,並通過運算式encodings.aliases.aliases來獲得所有編碼格式的別名與他們對應的編碼格式名稱。運算式encodings.aliases.aliases將傳回一個形式為{alias:name}的字典物件,其中alias為編碼格式的別名,name為編碼格式在 Python 中的名稱。
# …
# 使用編碼格式 u8 開啟檔案 utf8.txt
file = open('utf8.txt', 'r', encoding='u8')
print(file.read())這是編碼格式為 utf-8 的檔案解碼或編碼的字元應該與 encoding 參數對應的編碼格式相容
事實上,在呼叫open函式時,encoding參數所表示編碼格式可以與被開啟的文字檔案的編碼格式不同,但無論如何,在之後通過檔案物件讀取和寫入內容時,被解碼或編碼的字元需要與encoding參數所表示編碼格式相容,否則可能導致例外狀況。
如果檔案被真實的儲存,那麽最終檔案可能保留其原有的編碼格式,或采用encoding參數所表示編碼格式,或甚至改變為utf8,這取決於編碼格式的相容性(以避免出現亂碼)。
比如,使用編碼格式utf8開啟編碼格式為ascii的檔案,可以正常的讀取和寫入文字,因為utf8與ascii相容,只不過最終檔案的編碼格式可能是utf8,如果檔案被真實儲存的話。
在下面的範例中,雖然我們使用編碼格式ascii開啟了編碼格式為utf8的檔案diff.txt,但儲存檔案之後,diff.txt的編碼格式依然為utf8。
# 請將命令列跳躍至腳本檔案 diff_encoding.py 所在的目錄,然後執行他
# 使用編碼格式 ascii 開啟編碼格式為 utf8 的檔案 diff.txt
file = open('diff.txt', 'r+', encoding='ascii')
# 無法讀取與 ascii 不相容的 utf8 字元
try: file.readline()
except UnicodeDecodeError as e: print(e)
# 無法寫入與 ascii 不相容的 utf8 字元
try: file.write('你好!')
except UnicodeEncodeError as e: print(e)
# 可以寫入 ascii 字元
file.writelines(['\nHello!'])
# 檔案 diff.txt 被儲存之後,編碼格式依然為 utf8這裏的字元將以編碼格式 ascii 被讀取# 讀取 utf8 字元
'ascii' codec can't decode byte 0xe8 in position 0: ordinal not in range(128)
# 寫入 utf8 字元
'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)指定編碼和解碼錯誤的處理方式
open函式的errors參數可用於設定如何處理編碼或解碼錯誤,該參數的作用可能不會在呼叫open函式時體現,因為編碼和解碼通常由open函式傳回的檔案物件執行,Python 檔案物件將按照errors參數給出的錯誤處理方式來處理可能出現的編碼和解碼錯誤。
以下是errors參數的有效取值。
- None,'strict'
errors參數的預設值None與'strict'具有相同的效果,他們表示當出現編碼或解碼錯誤時,將擲回例外狀況ValueError。- 'ignore'
'ignore'表示忽略出現的編碼和解碼錯誤,當然,這將導致不可預知的結果,因為出現錯誤的內容會被丟棄。比如,Python 檔案物件讀取的內容不會包含編碼或解碼錯誤的部分,檔案物件不會將編碼或解碼錯誤的內容寫入到檔案中。- 'replace'
'replace'表示會將出現編碼或解碼錯誤的內容取代為特定的字元,比如問號。這裏有個有趣的現象,當你使用編碼格式
ascii解碼編碼格式為utf8的文字檔案時,一個漢字可能被取代為多個問號。當你使用編碼格式ascii將漢字寫入文字檔案時,一個漢字只會被取代為一個問號。- 'backslashreplace'
'backslashreplace'表示會將出現編碼或解碼錯誤的內容取代為表示其值的內容(形式可能為\uHHHH或\xHH,其中H為十六進位數值)。比如,當open函式的encoding參數為'ascii'時,將與編碼格式ascii不相容的字元寫入檔案,會導致這些字元被取代為類似於\uHHHH的字串。- 'xmlcharrefreplace'
'xmlcharrefreplace'表示會將出現編碼錯誤的字元取代為該字元對應的 Unicode 編碼值(形式為n[n…];,其中n為十進位數值)。需要指出,'xmlcharrefreplace'並不會處理解碼錯誤,因此,當出現解碼錯誤時,可能會有例外狀況被擲回。- 'namereplace'
'namereplace'表示會將出現編碼錯誤的字元取代為該字元在編碼格式中的名稱(形式為\N{name},其中name為字元的名稱)。需要指出,'namereplace'並不會處理解碼錯誤,因此,當出現解碼錯誤時,可能會有例外狀況被擲回。- 'surrogateescape'
'surrogateescape'表示如果 Unicode 編碼值在DC80與DCFF之間的字元出現了編碼錯誤,那麽出錯的字元將被取代為代理碼(比如,編碼值為DC80的字元會被取代為值為80的代理碼),這樣在進行解碼時,代理碼便可再次被取代回原本的字元(比如,值為80的代理碼被取代回編碼值為DC80的字元)。
在下面的範例中,我們采用不同的錯誤處理方式讀取檔案error.txt,該檔案包含了漢字和英文字母,這將導致編碼格式為ascii的 Python 檔案物件在讀取檔案時會出現解碼錯誤。
# 請將命令列跳躍至腳本檔案 error_read.py 所在的目錄,然後執行他
# 函式 read 將開啟檔案並讀取其中的內容
def read(e):
try:
file = open('error.txt', 'r', encoding='ascii', errors=e)
# 顯示檔案中的內容
text = file.read()
print(f'{e} {text}')
except Exception as err:
print(f'{e} {err}')
# 使用不同的錯誤處理方式讀取檔案 error.txt
read('strict')
read('ignore')
read('replace')
read('backslashreplace')今天 is good# strict 會擲回例外狀況
strict 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
# ignore 會丟棄出錯的內容
ignore is good
# replace 會將出錯的內容取代為特定字元
replace ������ is good
# backslashreplace 會將出錯的內容取代為表示其值的內容
backslashreplace \xe4\xbb\x8a\xe5\xa4\xa9 is good在下面的範例中,我們采用不同的錯誤處理方式,將包含漢字和英文字母的字串寫入文字檔案error.txt,由於 Python 檔案物件的編碼格式為ascii,因此將出現編碼錯誤。
# 請將命令列跳躍至腳本檔案 error_write.py 所在的目錄,然後執行他
# 函式 write 將開啟檔案並寫入一些內容
def write(e):
try:
file = open(f'error_{e}.txt', 'w', encoding='ascii', errors=e)
# 將內容寫入檔案
file.write('今天 is good')
except Exception as err:
print(f'{e} {err}')
# 使用不同的錯誤處理方式寫入檔案
write('strict')
write('ignore')
write('replace')
write('backslashreplace')
write('xmlcharrefreplace')
write('namereplace')
# 檢視檔案中被寫入的內容
for i in ('strict', 'ignore', 'replace', 'backslashreplace', 'xmlcharrefreplace', 'namereplace'):
fn = f'error_{i}.txt'
file = open(fn, 'r', encoding='ascii')
print(f'{fn} {file.read()}')# strict 會擲回例外狀況
strict 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
error_strict.txt
# ignore 會丟棄出錯的字元
error_ignore.txt is good
# replace 會將出錯的字元取代為特定字元
error_replace.txt ?? is good
# backslashreplace 會將出錯的字元取代為表示其值的內容
error_backslashreplace.txt \u4eca\u5929 is good
# xmlcharrefreplace 會將出錯的字元取代為該字元對應的 Unicode 編碼值
error_xmlcharrefreplace.txt 今天 is good
# namereplace 會將出錯的字元取代為該字元在編碼格式中的名稱
error_namereplace.txt \N{CJK UNIFIED IDEOGRAPH-4ECA}\N{CJK UNIFIED IDEOGRAPH-5929} is good在下面的範例中,我們采用錯誤處理方式surrogateescape,將內容\udc80\udc81\udc82寫入檔案surrogate.txt,然後讀取該檔案,發現其內容依然為\udc80\udc81\udc82。
如果改為其他的錯誤處理方式,比如replace,那麽再次讀取檔案後,內容將不再是\udc80\udc81\udc82。
# 請將命令列跳躍至腳本檔案 surrogateescape.py 所在的目錄,然後執行他
# 嘗試將 \udc80\udc81\udc82 寫入檔案 surrogate.txt
file = open('surrogate.txt', 'w', encoding='utf8', errors='surrogateescape')
file.write('\udc80\udc81\udc82')
# 讀取檔案 surrogate.txt 中的內容,並顯示其 Unicode 編碼值
file = open('surrogate.txt', 'r', encoding='utf8', errors='surrogateescape')
for c in file.read():
print(hex(ord(c)))0xdc80
0xdc81
0xdc82指定換行₁的處理方式
不同的作業系統,可能會以不同的字元來表示文字檔案中的換行₁,比如,UNIX/Linux/macOS 通常會將\n視為換行₁(較早版本的 macOS 將\r視為換行₁),Windows 通常會將\r\n視為換行₁。
在使用open函式時,你可以通過該函式的newline參數來設定如何處理文字檔案中的換行₁,這主要影響 Python 檔案物件的readline和readlines方法,不同的newline參數會導致readline和readlines方法將不同的字元視為一行的結束。
newline參數可以是以下有效取值之一。
- None
None是參數newline的預設值,他表示當你讀取文字檔案時,檔案中的\n,\r\n或\r均被視為一行的結束,並且\r\n和\r會被取代為\n,當你向檔案寫入\n時,\n將被轉換為系統換行₁方式所對應的字元(即運算式os.linesep的傳回值,他可能是\n,\r\n或\r)。- ''
與
None類似,''表示當你讀取文字檔案時,檔案中的\n,\r\n或\r均被視為一行的結束,但\r\n和\r不會被取代為\n,當你向檔案寫入\n時,\n不會發生任何變化。- '\n','\r\n','\r'
'\n','\r\n','\r'表示當你讀取文字檔案時,分別將檔案中的\n,\r\n,\r視為一行的結束,當你向檔案寫入\n時,將根據需要將其轉換為\r\n或\r。
在下面的範例中,我們有三個文字檔案line_n.txt,line_rn.txt,line_r.txt,他們分別包含內容\n\n,\r\n\r\n,\r\r。以不同的換行₁方式開啟他們之後,Python 檔案物件的readlines方法將傳回不同的結果。
# 請將命令列跳躍至腳本檔案 newline_read.py 所在的目錄,然後執行他
# 函式 read_newline 將采用指定的換行₁方式讀取不同的檔案
def read_newline(nl=None):
# 依次讀取以 \n,\r\n,\r 為換行₁的檔案
for name in ('n', 'rn', 'r'):
fn = f'line_{name}.txt'
file = open(fn, 'r', encoding='utf8', newline=nl)
# 顯示檔案中的每一行
print(file.readlines())
# 采用不同的換行₁方式讀取不同的檔案
read_newline()
read_newline('')
read_newline('\n')
read_newline('\r\n')
read_newline('\r')# 預設換行₁方式將 \n,\r\n,\r 視為行的結束,並取代為 \n
['\n', '\n']
['\n', '\n']
['\n', '\n']
# 換行₁方式 '' 將 \n,\r\n,\r 視為行的結束
['\n', '\n']
['\r\n', '\r\n']
['\r', '\r']
# 換行₁方式 '\n' 將 \n 視為行的結束
['\n', '\n']
['\r\n', '\r\n']
['\r\r']
# 換行₁方式 '\r\n' 將 \r\n 視為行的結束
['\n\n']
['\r\n', '\r\n']
['\r\r']
# 換行₁方式 '\r' 將 \r 視為行的結束
['\n\n']
['\r', '\n\r', '\n']
['\r', '\r']在下面的範例中,我們采用不同的換行₁方式將相同的內容\n\r\n\r寫入到不同的文字檔案中,然後檢視他們對字元\n的處理情況。
# 請將命令列跳躍至腳本檔案 newline_write.py 所在的目錄,然後執行他
no = 1
# 采用不同的換行₁方式寫入相同的內容
for nl in (None, '', '\n', '\r\n', '\r'):
fn = f'line_w_{no}.txt'
file = open(fn, 'w', encoding='utf8', newline=nl)
file.writelines(['\n', '\r\n', '\r'])
no += 1
# 檢視檔案中被寫入的內容
for i in range(1, 6):
file = open(f'line_w_{i}.txt', 'r', encoding='utf8', newline='')
print(file.read().encode())# 預設換行₁方式會將 \n 取代為 \r\n
b'\r\n\r\r\n\r'
# 換行₁方式 '' 不會改變 \n
b'\n\r\n\r'
# 換行₁方式 '\n' 不會改變 \n
b'\n\r\n\r'
# 換行₁方式 '\r\n' 會將 \n 取代為 \r\n
b'\r\n\r\r\n\r'
# 換行₁方式 '\r' 會將 \n 取代為 \r
b'\r\r\r\r'自訂檔案描述器的建立方式
open函式的opener參數是一個傳回檔案描述器的函式(或方法),他應擁有形式類似於(file,flags)的參數,其中file和flags的值將根據open函式的其他參數來確定,傳回的檔案描述器將用於開啟檔案。
在下面的範例中,我們定義了函式myopener作為opener參數的值,該函式只會傳回用於讀取操作的檔案描述器,因此,所有對檔案的寫入操作都將是無效的。
# 請將命令列跳躍至腳本檔案 open_opener.py 所在的目錄,然後執行他
import os
# 只會傳回用於讀取操作的檔案描述器
def myopener(file, flags):
print(f'file {file} flags {flags}')
return os.open(file, os.O_RDONLY)
# 無論選擇哪種開啟模式,檔案都是唯讀的
file = open('opener.txt', 'r', encoding='utf8', opener=myopener)
print(file.read())
file = open('opener.txt', 'w', encoding='utf8', opener=myopener)
# 雖然沒有例外狀況發生,但檔案 opener.txt 中的內容不會發生變化
file.write('寫點東西')我始終是唯讀的file opener.txt flags 32896
我始終是唯讀的
file opener.txt flags 33665open 函式所傳回的檔案物件的型別
open函式的傳回值是一個檔案物件,該檔案物件的型別由open函式的參數來決定。
當open函式嘗試開啟文字檔案時,其傳回的檔案物件的型別為TextIOWrapper。
當open函式嘗試使用緩沖區開啟二進位檔案時,其傳回的檔案物件的型別可能是BufferedReader(唯讀),BufferedWriter(唯寫),BufferedRandom(讀取及寫入)中的一種。
當open函式嘗試開啟二進位檔案並停用緩沖區時,其傳回的檔案物件的型別為FileIO。
# 請將命令列跳躍至腳本檔案 file_object.py 所在的目錄,然後執行他
# 讀取文字檔案
print(type(open('file_object.txt', 'r')))
# 讀取二進位檔案
print(type(open('file_object.txt', 'rb')))
# 寫入二進位檔案
print(type(open('file_object.txt', 'wb')))
# 讀取及寫入二進位檔案
print(type(open('file_object.txt', 'w+b')))
# 停用緩沖
print(type(open('file_object.txt', 'rb', 0)))<class '_io.TextIOWrapper'>
<class '_io.BufferedReader'>
<class '_io.BufferedWriter'>
<class '_io.BufferedRandom'>
<class '_io.FileIO'>