如何使用 Python open 函式開啟檔案?以及編碼,解碼,換行,緩沖等問題
本節所講述的是如何在 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 所在的目錄,然後執行他
# 使用 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')
今天天氣不錯
今天天氣不錯
為 Python open 函式指定檔案開啟模式
Pythonopen
函式的mode
參數可用於設定檔案的開啟模式,並影響接下來的檔案操作,比如,當檔案以唯讀模式開啟時,你將無法對檔案進行寫入。mode
參數是一個字串,他可以是以下值之一,或他們的某種組合。
模式 作用 r 預設值,表示可讀取檔案中的內容 w 清空檔案中的內容,並可將新內容寫入檔案 a 可將內容寫入檔案,預設追加至檔案末尾 x 建立新檔案,並可將內容寫入其中 t 預設值,作為文字檔案開啟 b 作為二進位檔案開啟 + 額外允許讀取或寫入檔案
一般情況下,r
,w
,a
,x
中的一個需要存在於 Pythonopen
函式的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
不能同時出現,如果希望 Pythonopen
函式所開啟的檔案同時支援讀取和寫入操作,那麽應在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 mode
Python open 函式如何處理檔案不存在的情況?
當你選擇r
,w
和a
中的某一個作為mode
參數時, Python 的 open 函式將采用不同的方式來處理檔案不存在的情況。
對於r
模式,如果需要開啟的檔案不存在,那麽 Python open 函式將擲回例外狀況FileNotFoundError: [Errno …] No such file or directory: '…'
。對於w
和a
模式,如果需要開啟的檔案不存在,那麽 Python open 函式將立刻建立該檔案。
與以上提到的三種模式不同,x
模式並不處理檔案不存在的情況,相反的,如果被開啟的檔案已經存在,那麽 Python 的 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'
無論是否寫入新內容 Python open 函式都將在 w 模式下清空檔案中的內容
如果選擇w
作為檔案的開啟模式,那麽 Pythonopen
函式將清空被開啟檔案中的內容,即便接下來你並沒有使用該函式傳回的檔案物件,將新的內容寫入檔案。
在下面的範例中,雖然沒有通過 Python 檔案物件向檔案寫入資料,但檔案中的內容將被清空。
# 請將命令列跳躍至腳本檔案 w_clear.py 所在的目錄,然後執行他
# 檔案 data.txt 中的內容將被清空
open('data.txt', 'w')
一些資料
開啟二進位檔案時不需要為 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 所在的目錄,然後執行他
# 設定緩沖區的大小為 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 所在的目錄,然後執行他
# 啟用行緩沖策略
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 所在的目錄,然後執行他
# 使用編碼格式 utf-8 開啟檔案 utf8.txt
file = open('utf8.txt', 'r', encoding='utf8')
print(file.read())
這是編碼格式為 utf-8 的檔案
這是編碼格式為 utf-8 的檔案
Python open 函式支援編碼格式的別名並且不區分名稱的大小寫
對於某種編碼格式,Python 可能為其定義了別名,以方便開發人員書寫程式碼,比如,utf8
,utf-8
和utf_8
在執行結果上是相同的。此外,Pythonopen
函式也不區分編碼格式的名稱的大小寫,書寫utf8
,Utf8
或UTF8
在執行結果上是相同的。
你可以匯入 Python 的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 的檔案
解碼或編碼的字元應該與 Python open 函式的 encoding 參數對應的編碼格式相容
事實上,在呼叫 Pythonopen
函式時,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)
為 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 編碼值在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
為 Python open 函式指定換行₁的處理方式
不同的作業系統,可能會以不同的字元來表示文字檔案中的換行₁,比如,UNIX/Linux/macOS 通常會將\n
視為換行₁(較早版本的 macOS 將\r
視為換行₁),Windows 通常會將\r\n
視為換行₁。
在使用 Python 的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'
為 Python open 函式自訂檔案描述器的建立方式
Pythonopen
函式的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 33665
Python open 函式所傳回的檔案物件的型別
如本節所述,Pythonopen
函式的傳回值是一個檔案物件,該檔案物件的型別由open
函式的參數來決定。
當 Pythonopen
函式嘗試開啟文字檔案時,其傳回的檔案物件的型別為TextIOWrapper
。
當 Pythonopen
函式嘗試使用緩沖區開啟二進位檔案時,其傳回的檔案物件的型別可能是BufferedReader
(唯讀),BufferedWriter
(唯寫),BufferedRandom
(讀取及寫入)中的一種。
當 Pythonopen
函式嘗試開啟二進位檔案並停用緩沖區時,其傳回的檔案物件的型別為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'>
程式碼
src/zh-hant/file_system/file_handling/open·codebeatme/python·GitHub