如何使用 Python open 函式開啟檔案?以及編碼,解碼,換行,緩沖等問題

閱讀 29:41·字數 8908·發佈 
Youtube 頻道
訂閱 133

本節所講述的是如何在 Python 中開啟檔案,至於檔案的讀取和寫入,請參考如何使用 Python 檔案物件讀取及寫入檔案?以及檔案指標,關閉檔案,取得檔案物件資訊等問題一節。本節的“換行₁”一詞是指產生新的一行,類似於在編輯器中按下Enter鍵。

使用 Python open 函式開啟檔案

通過 Python 的內建函式open,你可以快速的開啟某個檔案,這不像其他的一些程式設計語言,比如 C#,需要預先匯入特定的模組或命名空間。當然,Pythonopen函式的作用是開啟檔案而不是存取檔案中的內容,你需要呼叫其傳回的檔案物件(file object)的相關方法來完成內容的讀取或寫入。

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

file 參數

file參數是一個表示檔案路徑的字串,或整合檔案的 Python 檔案描述器(file descriptor)。如果該參數是檔案路徑,那麽closefd參數必須是True,否則將引發例外狀況ValueError: Cannot use closefd=False with file name

Python 檔案描述器可通過os模組的open函式建立,但請區別於 Python 內建函式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函式(不是 Python 內建函式open)建立了一個檔案描述器,並使用該檔案描述器開啟了檔案,由於closefd參數為False,因此當檔案被關閉之後,你依然可以通過檔案描述器再次開啟檔案。

需要指出的是,使用檔案描述器是沒有必要的,一般情況下,應直接呼叫 Python 函式open來開啟檔案。

open_fd.py
# 請將命令列跳躍至腳本檔案 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')
info.txt
今天天氣不錯
今天天氣不錯

為 Python open 函式指定檔案開啟模式

Pythonopen函式的mode參數可用於設定檔案的開啟模式,並影響接下來的檔案操作,比如,當檔案以唯讀模式開啟時,你將無法對檔案進行寫入。mode參數是一個字串,他可以是以下值之一,或他們的某種組合。


模式作用
r預設值,表示可讀取檔案中的內容
w清空檔案中的內容,並可將新內容寫入檔案
a可將內容寫入檔案,預設追加至檔案末尾
x建立新檔案,並可將內容寫入其中
t預設值,作為文字檔案開啟
b作為二進位檔案開啟
+額外允許讀取或寫入檔案

一般情況下,rwax中的一個需要存在於 Pythonopen函式的mode參數中,否則例外狀況ValueError: Must have exactly one of create/read/write/append mode and at most one plus將被擲回,並且rwax不能同時出現,比如,rwra這樣的模式是無效的,例外狀況ValueError: must have exactly one of create/read/write/append mode將被擲回。

由於rwax不能同時出現,如果希望 Pythonopen函式所開啟的檔案同時支援讀取和寫入操作,那麽應在mode參數中增加+,比如,r+w+

此外,一些模式組合是明顯無效的,比如,rtb是無效的,因為無法將一個檔案同時作為文字檔案和二進位檔案開啟。

Python 3.11 版本移除了U模式。

mode.py
# 請將命令列跳躍至腳本檔案 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 mode

Python open 函式如何處理檔案不存在的情況?

當你選擇rwa中的某一個作為mode參數時, Python 的 open 函式將采用不同的方式來處理檔案不存在的情況。

對於r模式,如果需要開啟的檔案不存在,那麽 Python open 函式將擲回例外狀況FileNotFoundError: [Errno …] No such file or directory: '…'。對於wa模式,如果需要開啟的檔案不存在,那麽 Python open 函式將立刻建立該檔案。

與以上提到的三種模式不同,x模式並不處理檔案不存在的情況,相反的,如果被開啟的檔案已經存在,那麽 Python 的 open 函式將擲回例外狀況FileExistsError: [Errno …] File exists: '…'

在下面的範例中,使用a模式開啟檔案no.md,將導致該檔案被自動建立。

file_exists.py
# 請將命令列跳躍至腳本檔案 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'

無論是否寫入新內容 Python open 函式都將在 w 模式下清空檔案中的內容

如果選擇w作為檔案的開啟模式,那麽 Pythonopen函式將清空被開啟檔案中的內容,即便接下來你並沒有使用該函式傳回的檔案物件,將新的內容寫入檔案。

在下面的範例中,雖然沒有通過 Python 檔案物件向檔案寫入資料,但檔案中的內容將被清空。

w_clear.py
# 請將命令列跳躍至腳本檔案 w_clear.py 所在的目錄,然後執行他
# 檔案 data.txt 中的內容將被清空
open('data.txt', 'w')
data.txt
一些資料

開啟二進位檔案時不需要為 Python open 函式指定編碼格式

對於b模式,你不需要為 Pythonopen函式指定檔案的編碼格式(即encoding參數),否則將引發例外狀況ValueError: binary mode doesn't take an encoding argument

為 Python open 函式指定緩沖策略

通過 Pythonopen函式的buffering參數,可以為open函式傳回的檔案物件指定緩沖策略,在緩沖策略的作用下,Python 檔案物件會從緩沖區讀取資料或將資料寫入緩沖區,而不是直接針對檔案進行讀取和寫入,這樣做的目的是為了減少儲存裝置的存取次數,提高程式碼的執行效率。

對於二進位檔案,Pythonopen函式的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
# 請將命令列跳躍至腳本檔案 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')

Python open 函式如何指定文字檔案采用行緩沖策略?

對於文字檔案,如果 Pythonopen函式的buffering參數為1,那麽將采用行緩沖策略,無論open函式的newline參數指定了哪種換行₁方式,當通過檔案物件寫入\n\r\n\r時,都將使緩沖區中的資料被儲存至檔案。

這裏需要說明的是,你必須明確的通過 Python 檔案物件將\n\r\n\r寫入,呼叫檔案物件的writelines方法並不能觸發行緩沖策略,如果被寫入的字串不包含\n\r\n\r

在下面的範例中,呼叫方法writelines之後,abc被存放在緩沖區,因為沒有出現\n\r\n\r

buffer_line.py
# 請將命令列跳躍至腳本檔案 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')

為 Python open 函式指定檔案的編碼格式

當通過 Pythonopen函式開啟文字檔案時,你應該給出文字檔案的編碼,即open函式的encoding參數。當然,如果encoding參數被忽略或被設定為空值None,那麽open函式將采用 Pythonlocale模組的getencoding方法所傳回的編碼格式,即本機預設的編碼格式。

雖然 Python 支援大部分的檔案編碼格式,比如常見的utf8,但這並不意味著所有的編碼格式都能夠被 Python 處理。

encoding.py
# 請將命令列跳躍至腳本檔案 encoding.py 所在的目錄,然後執行他
# 使用編碼格式 utf-8 開啟檔案 utf8.txt
file = open('utf8.txt', 'r', encoding='utf8')
print(file.read())
utf8.txt
這是編碼格式為 utf-8 的檔案
這是編碼格式為 utf-8 的檔案

Python open 函式支援編碼格式的別名並且不區分名稱的大小寫

對於某種編碼格式,Python 可能為其定義了別名,以方便開發人員書寫程式碼,比如,utf8utf-8utf_8在執行結果上是相同的。此外,Pythonopen函式也不區分編碼格式的名稱的大小寫,書寫utf8Utf8UTF8在執行結果上是相同的。

你可以匯入 Python 的encodings模組,並通過運算式encodings.aliases.aliases來獲得所有編碼格式的別名與他們對應的編碼格式名稱。運算式encodings.aliases.aliases將傳回一個形式為{alias:name}的字典物件,其中alias為編碼格式的別名,name為編碼格式在 Python 中的名稱。

encoding.py
# …
# 使用編碼格式 u8 開啟檔案 utf8.txt
file = open('utf8.txt', 'r', encoding='u8')
print(file.read())
這是編碼格式為 utf-8 的檔案

解碼或編碼的字元應該與 Python open 函式的 encoding 參數對應的編碼格式相容

事實上,在呼叫 Pythonopen函式時,encoding參數所表示編碼格式可以與被開啟的文字檔案的編碼格式不同,但無論如何,在之後通過檔案物件讀取和寫入內容時,被解碼或編碼的字元需要與encoding參數所表示編碼格式相容,否則可能導致例外狀況。

如果檔案被真實的儲存,那麽最終檔案可能保留其原有的編碼格式,或采用encoding參數所表示編碼格式,或甚至改變為utf8,這取決於編碼格式的相容性(以避免出現亂碼)。

比如,使用編碼格式utf8開啟編碼格式為ascii的檔案,可以正常的讀取和寫入文字,因為utf8ascii相容,只不過最終檔案的編碼格式可能是utf8,如果檔案被真實儲存的話。

在下面的範例中,雖然我們使用編碼格式ascii開啟了編碼格式為utf8的檔案diff.txt,但儲存檔案之後,diff.txt的編碼格式依然為utf8

diff_encoding.py
# 請將命令列跳躍至腳本檔案 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
diff.txt
這裏的字元將以編碼格式 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)

為 Python open 函式指定編碼和解碼錯誤的處理方式

Pythonopen函式的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為十六進位數值)。比如,當 Pythonopen函式的encoding參數為'ascii'時,將與編碼格式ascii不相容的字元寫入檔案,會導致這些字元被取代為類似於\uHHHH的字串。

'xmlcharrefreplace'

'xmlcharrefreplace'表示會將出現編碼錯誤的字元取代為該字元對應的 Unicode 編碼值(形式為&#n[n…];,其中n為十進位數值)。需要指出,'xmlcharrefreplace'並不會處理解碼錯誤,因此,當出現解碼錯誤時,可能會有例外狀況被擲回。

'namereplace'

'namereplace'表示會將出現編碼錯誤的字元取代為該字元在編碼格式中的名稱(形式為\N{name},其中name為字元的名稱)。需要指出,'namereplace'並不會處理解碼錯誤,因此,當出現解碼錯誤時,可能會有例外狀況被擲回。

'surrogateescape'

'surrogateescape'表示如果 Unicode 編碼值在DC80DCFF之間的字元出現了編碼錯誤,那麽出錯的字元將被取代為代理碼(比如,編碼值為DC80的字元會被取代為值為80的代理碼),這樣在進行解碼時,代理碼便可再次被取代回原本的字元(比如,值為80的代理碼被取代回編碼值為DC80的字元)。

在下面的範例中,我們采用不同的錯誤處理方式讀取檔案error.txt,該檔案包含了漢字和英文字母,這將導致編碼格式為ascii的 Python 檔案物件在讀取檔案時會出現解碼錯誤。

error_read.py
# 請將命令列跳躍至腳本檔案 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')
error.txt
今天 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
# 請將命令列跳躍至腳本檔案 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
# 請將命令列跳躍至腳本檔案 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

為 Python open 函式指定換行₁的處理方式

不同的作業系統,可能會以不同的字元來表示文字檔案中的換行₁,比如,UNIX/Linux/macOS 通常會將\n視為換行₁(較早版本的 macOS 將\r視為換行₁),Windows 通常會將\r\n視為換行₁。

在使用 Python 的open函式時,你可以通過該函式的newline參數來設定如何處理文字檔案中的換行₁,這主要影響 Python 檔案物件的readlinereadlines方法,不同的newline參數會導致readlinereadlines方法將不同的字元視為一行的結束。

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.txtline_rn.txtline_r.txt,他們分別包含內容\n\n\r\n\r\n\r\r。以不同的換行₁方式開啟他們之後,Python 檔案物件的readlines方法將傳回不同的結果。

newline_read.py
# 請將命令列跳躍至腳本檔案 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
# 請將命令列跳躍至腳本檔案 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'

為 Python open 函式自訂檔案描述器的建立方式

Pythonopen函式的opener參數是一個傳回檔案描述器的函式(或方法),他應擁有形式類似於(file,flags)的參數,其中fileflags的值將根據open函式的其他參數來確定,傳回的檔案描述器將用於開啟檔案。

在下面的範例中,我們定義了函式myopener作為opener參數的值,該函式只會傳回用於讀取操作的檔案描述器,因此,所有對檔案的寫入操作都將是無效的。

open_opener.py
# 請將命令列跳躍至腳本檔案 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('寫點東西')
opener.txt
我始終是唯讀的
file opener.txt flags 32896
我始終是唯讀的
file opener.txt flags 33665

Python open 函式所傳回的檔案物件的型別

如本節所述,Pythonopen函式的傳回值是一個檔案物件,該檔案物件的型別由open函式的參數來決定。

當 Pythonopen函式嘗試開啟文字檔案時,其傳回的檔案物件的型別為TextIOWrapper

當 Pythonopen函式嘗試使用緩沖區開啟二進位檔案時,其傳回的檔案物件的型別可能是BufferedReader(唯讀),BufferedWriter(唯寫),BufferedRandom(讀取及寫入)中的一種。

當 Pythonopen函式嘗試開啟二進位檔案並停用緩沖區時,其傳回的檔案物件的型別為FileIO

file_object.py
# 請將命令列跳躍至腳本檔案 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'>

程式碼

src/zh-hant/file_system/file_handling/open·codebeatme/python·GitHub