io --- 用於處理流的核心工具

原始碼: Lib/io.py


概述

io 模組提供了 Python 用於處理各種 I/O 型別的主要工具。I/O 主要有三種類型:文字 I/O二進位制 I/O原始 I/O。這些都是通用類別,每種類別都可以使用各種後端儲存。屬於任一類別的具體物件都稱為檔案物件。其他常用術語有類檔案物件

無論屬於哪種類別,每個具體的流物件都具有多種能力:它可以是隻讀、只寫或讀寫的。它還可以支援任意的隨機訪問(向前或向後搜尋到任意位置),或只支援順序訪問(例如套接字或管道)。

所有流都嚴格檢查你提供給它們的資料型別。例如,將一個 str 物件傳遞給二進位制流的 write() 方法將會引發 TypeError。同樣,將一個 bytes 物件傳遞給文字流的 write() 方法也會引發該異常。

3.3 版更改: 過去會引發 IOError 的操作現在會引發 OSError,因為 IOError 現在是 OSError 的別名。

文字 I/O

文字 I/O 期望併產生 str 物件。這意味著,無論何時,當後端儲存原生為位元組(例如檔案)時,資料的編碼和解碼都會透明地進行,同時還會選擇性地轉換平臺特定的換行符。

建立文字流的最簡單方法是使用 open(),並可選擇指定編碼:

f = open("myfile.txt", "r", encoding="utf-8")

記憶體中的文字流也可以作為 StringIO 物件使用:

f = io.StringIO("some initial text data")

備註

當使用非阻塞流時,請注意,如果流無法立即執行操作,對文字 I/O 物件的讀取操作可能會引發 BlockingIOError

文字流 API 在 TextIOBase 的文件中有詳細描述。

二進位制 I/O

二進位制 I/O(也稱為緩衝 I/O)期望接收類位元組物件併產生 bytes 物件。不執行任何編碼、解碼或換行符轉換。這類流可用於所有非文字資料,也可用於需要手動控制文字資料處理的情況。

建立二進位制流的最簡單方法是使用 open(),並在模式字串中加入 'b'

f = open("myfile.jpg", "rb")

記憶體中的二進位制流也可以作為 BytesIO 物件使用:

f = io.BytesIO(b"some initial binary data: \x00\x01")

二進位制流 API 在 BufferedIOBase 的文件中有詳細描述。

其他庫模組可能提供了建立文字或二進位制流的額外方式。例如 socket.socket.makefile()

原始 I/O

原始 I/O(也稱為無緩衝 I/O)通常用作二進位制流和文字流的底層構建塊;使用者程式碼很少需要直接操作原始流。儘管如此,你還是可以透過在二進位制模式下開啟檔案並停用緩衝來建立一個原始流:

f = open("myfile.jpg", "rb", buffering=0)

原始流 API 在 RawIOBase 的文件中有詳細描述。

文字編碼

TextIOWrapperopen() 的預設編碼是與區域設定相關的(locale.getencoding())。

然而,許多開發者在開啟以 UTF-8 編碼的文字檔案(例如 JSON、TOML、Markdown 等)時會忘記指定編碼,因為大多數 Unix 平臺預設使用 UTF-8 區域設定。這會導致 bug,因為對於大多數 Windows 使用者來說,其區域設定編碼並非 UTF-8。例如:

# May not work on Windows when non-ASCII characters in the file.
with open("README.md") as f:
    long_description = f.read()

因此,強烈建議在開啟文字檔案時明確指定編碼。如果你想使用 UTF-8,請傳遞 encoding="utf-8"。若要使用當前區域設定的編碼,自 Python 3.10 起支援 encoding="locale"

參見

Python UTF-8 模式

Python UTF-8 模式可用於將預設編碼從特定於區域設定的編碼更改為 UTF-8。

PEP 686

Python 3.15 將預設啟用 Python UTF-8 模式

可選的 EncodingWarning

在 3.10 版新加入: 更多詳情請參閱 PEP 597

要找出哪裡使用了預設的區域設定編碼,你可以啟用 -X warn_default_encoding 命令列選項,或設定 PYTHONWARNDEFAULTENCODING 環境變數。當使用預設編碼時,這將發出一個 EncodingWarning

如果你提供的 API 使用 open()TextIOWrapper,並將 encoding=None 作為引數傳遞,你可以使用 text_encoding(),這樣如果 API 的呼叫者沒有傳遞 encoding,就會發出一個 EncodingWarning。不過,對於新的 API,請考慮預設使用 UTF-8(即 encoding="utf-8")。

高層模組介面

io.DEFAULT_BUFFER_SIZE

一個整數,表示模組的緩衝 I/O 類所使用的預設緩衝區大小。open() 如果可能,會使用檔案的 blksize(透過 os.stat() 獲得)。

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

這是內建函式 open() 的別名。

此函式會引發一個審計事件 open,其引數為 pathmodeflagsmodeflags 引數可能已根據原始呼叫被修改或推斷得出。

io.open_code(path)

以模式 'rb' 開啟所提供的檔案。當打算將檔案內容視為可執行程式碼時,應使用此函式。

path 應該是一個 str 並且是絕對路徑。

此函式的行為可能會被先前對 PyFile_SetOpenCodeHook() 的呼叫所覆蓋。然而,假設 path 是一個 str 型別的絕對路徑,open_code(path) 的行為應始終與 open(path, 'rb') 相同。覆蓋其行為的目的是為了對檔案進行額外的驗證或預處理。

在 3.8 版本加入。

io.text_encoding(encoding, stacklevel=2, /)

這是一個輔助函式,適用於使用 open()TextIOWrapper 並且帶有 encoding=None 引數的可呼叫物件。

如果 encoding 不為 None,此函式返回 encoding。否則,它將根據UTF-8 模式返回 "locale""utf-8"

如果 sys.flags.warn_default_encoding 為真且 encodingNone,此函式會發出一個 EncodingWarningstacklevel 指定警告發出的位置。例如:

def read_text(path, encoding=None):
    encoding = io.text_encoding(encoding)  # stacklevel=2
    with open(path, encoding) as f:
        return f.read()

在此示例中,會為 read_text() 的呼叫者發出一個 EncodingWarning

更多資訊請參閱文字編碼

在 3.10 版本加入。

在 3.11 版更改: 當 UTF-8 模式啟用且 encodingNone 時,text_encoding() 返回 "utf-8"。

exception io.BlockingIOError

這是內建異常 BlockingIOError 的相容性別名。

exception io.UnsupportedOperation

一個繼承自 OSErrorValueError 的異常,當在流上呼叫不支援的操作時引發。

參見

sys

包含標準 IO 流:sys.stdinsys.stdoutsys.stderr

類層次結構

I/O 流的實現被組織成一個類的層次結構。首先是抽象基類 (ABC),它們用於指定流的各種類別,然後是提供標準流實現的具體類。

備註

抽象基類還為某些方法提供了預設實現,以幫助實現具體的流類。例如,BufferedIOBase 提供了 readinto()readline() 的未最佳化實現。

I/O 層次結構的頂層是抽象基類 IOBase。它定義了流的基本介面。但是請注意,讀寫流之間沒有分離;如果實現不支援某個給定的操作,允許引發 UnsupportedOperation

RawIOBase ABC 擴充套件了 IOBase。它處理流中位元組的讀寫。FileIO 子類化了 RawIOBase,為機器檔案系統中的檔案提供介面。

BufferedIOBase ABC 擴充套件了 IOBase。它處理原始二進位制流 (RawIOBase) 上的緩衝。它的子類 BufferedWriterBufferedReaderBufferedRWPair 分別緩衝可寫、可讀以及可讀可寫的原始二進位制流。BufferedRandom 為可查詢的流提供了緩衝介面。另一個 BufferedIOBase 的子類 BytesIO 是一個記憶體中的位元組流。

TextIOBase ABC 擴充套件了 IOBase。它處理其位元組表示文字的流,並處理與字串之間的編碼和解碼。TextIOWrapper 繼承自 TextIOBase,是緩衝原始流 (BufferedIOBase) 的緩衝文字介面。最後,StringIO 是一個用於文字的記憶體流。

引數名稱不屬於規範的一部分,只有 open() 的引數才意在用作關鍵字引數。

下表總結了 io 模組提供的 ABC:

ABC (抽象基類)

繼承自

存根方法 (Stub Methods)

混入方法和屬性 (Mixin Methods and Properties)

IOBase

fileno, seek, 和 truncate

close, closed, __enter__, __exit__, flush, isatty, __iter__, __next__, readable, readline, readlines, seekable, tell, writable, 和 writelines

RawIOBase

IOBase

readintowrite

繼承自 IOBase 的方法、readreadall

BufferedIOBase

IOBase

detach, read, read1, 和 write

繼承自 IOBase 的方法、readintoreadinto1

TextIOBase

IOBase

detach, read, readline, 和 write

繼承自 IOBase 的方法、encoding, errors, 和 newlines

I/O 基類

class io.IOBase

所有 I/O 類的抽象基類。

這個類為許多方法提供了空的抽象實現,派生類可以有選擇地覆蓋這些實現;預設實現代表了一個不可讀、不可寫或不可查詢的檔案。

儘管 IOBase 沒有宣告 read()write(),因為它們的簽名會變化,但實現和客戶端應將這些方法視為介面的一部分。此外,當呼叫不支援的操作時,實現可能會引發 ValueError(或 UnsupportedOperation)。

從檔案中讀取或寫入檔案的二進位制資料的基本型別是 bytes。其他類位元組物件也可用作方法引數。文字 I/O 類處理 str 資料。

請注意,對一個已關閉的流呼叫任何方法(甚至是查詢)都是未定義的。在這種情況下,實現可能會引發 ValueError

IOBase(及其子類)支援迭代器協議,這意味著可以對 IOBase 物件進行迭代,以產生流中的行。行的定義略有不同,取決於流是二進位制流(產生位元組)還是文字流(產生字串)。請參閱下面的 readline()

IOBase 也是一個上下文管理器,因此支援 with 語句。在此示例中,filewith 語句塊完成後被關閉——即使發生異常也是如此:

with open('spam.txt', 'w') as file:
    file.write('Spam and eggs!')

IOBase 提供了這些資料屬性和方法:

close()

重新整理並關閉此流。如果檔案已經關閉,此方法無效。一旦檔案關閉,對檔案的任何操作(例如讀或寫)都將引發 ValueError

為方便起見,允許多次呼叫此方法;但只有第一次呼叫會生效。

closed

如果流已關閉,則為 True

fileno()

如果流存在,則返回其底層的整數檔案描述符。如果 IO 物件不使用檔案描述符,則引發 OSError

flush()

如果適用,重新整理流的寫緩衝區。對於只讀和非阻塞流,此操作無效。

isatty()

如果流是互動式的(即連線到終端/tty 裝置),則返回 True

readable()

如果可以從流中讀取,則返回 True。如果為 Falseread() 將引發 OSError

readline(size=-1, /)

從流中讀取並返回一行。如果指定了 size,則最多讀取 size 個位元組。

對於二進位制檔案,行終止符始終為 b'\n';對於文字檔案,可以使用 open()newline 引數來選擇可識別的行終止符。

readlines(hint=-1, /)

從流中讀取並返回一個行的列表。可以指定 hint 來控制讀取的行數:如果到目前為止所有行的總大小(位元組/字元數)超過 hint,則不再讀取更多行。

hint 值為 0 或更小,以及 None,都被視為無提示。

請注意,已經可以使用 for line in file: ... 來迭代檔案物件,而無需呼叫 file.readlines()

seek(offset, whence=os.SEEK_SET, /)

將流的位置更改為給定的位元組 offset,相對於 whence 指示的位置進行解釋,並返回新的絕對位置。whence 的值有:

  • os.SEEK_SET0 – 流的開始(預設);offset 應為零或正數

  • os.SEEK_CUR1 – 當前流位置;offset 可以是負數

  • os.SEEK_END2 – 流的末尾;offset 通常為負數

在 3.1 版新加入: SEEK_* 常量。

在 3.3 版新加入: 一些作業系統可能支援其他值,例如 os.SEEK_HOLEos.SEEK_DATA。檔案的有效值可能取決於它是以文字模式還是二進位制模式開啟。

seekable()

如果流支援隨機訪問,則返回 True。如果為 Falseseek()tell()truncate() 將引發 OSError

tell()

返回當前流的位置。

truncate(size=None, /)

將流的大小調整為給定的 size 位元組(如果未指定 size,則為當前位置)。當前流的位置不變。此調整大小可以擴充套件或縮小當前檔案大小。在擴充套件的情況下,新檔案區域的內容取決於平臺(在大多數系統上,額外的位元組用零填充)。返回新的檔案大小。

在 3.5 版更改: 現在,Windows 在擴充套件檔案時會用零填充。

writable()

如果流支援寫入,則返回 True。如果為 Falsewrite()truncate() 將引發 OSError

writelines(lines, /)

向流中寫入一個行的列表。不會新增行分隔符,因此通常提供的每一行末尾都應有行分隔符。

__del__()

為物件銷燬做準備。IOBase 提供了此方法的預設實現,它會呼叫例項的 close() 方法。

class io.RawIOBase

原始二進位制流的基類。它繼承自 IOBase

原始二進位制流通常提供對底層作業系統裝置或 API 的低階訪問,並且不嘗試將其封裝在高階原語中(此功能在緩衝二進位制流和文字流的更高級別完成,本頁稍後將描述)。

RawIOBase 除了 IOBase 的方法外,還提供了這些方法:

read(size=-1, /)

從物件中讀取最多 size 個位元組並返回。為方便起見,如果 size 未指定或為 -1,則返回直到 EOF 的所有位元組。否則,只進行一次系統呼叫。如果作業系統呼叫返回的位元組數少於 size,則可能返回少於 size 的位元組。

如果返回 0 位元組,並且 size 不為 0,這表示檔案結束。如果物件處於非阻塞模式且沒有可用位元組,則返回 None

預設實現委託給 readall()readinto()

readall()

讀取並返回流中直到 EOF 的所有位元組,必要時對流進行多次呼叫。

readinto(b, /)

將位元組讀入預先分配的可寫的類位元組物件 b,並返回讀取的位元組數。例如,b 可能是一個 bytearray。如果物件處於非阻塞模式且沒有可用位元組,則返回 None

write(b, /)

將給定的類位元組物件 b 寫入底層原始流,並返回寫入的位元組數。這可能少於 b 的位元組長度,具體取決於底層原始流的特性,尤其是在非阻塞模式下。如果原始流設定為不阻塞,並且無法立即寫入任何單個位元組,則返回 None。呼叫者在此方法返回後可以釋放或修改 b,因此實現應僅在方法呼叫期間訪問 b

class io.BufferedIOBase

支援某種緩衝的二進位制流的基類。它繼承自 IOBase

RawIOBase 的主要區別在於方法 read()readinto()write() 將(分別)嘗試讀取請求的全部輸入或發出所有提供的資料。

此外,如果底層原始流處於非阻塞模式,當系統返回會阻塞時,write() 將引發 BlockingIOError 並帶有 BlockingIOError.characters_written 屬性,而 read() 將返回已讀取的資料,或者如果沒有可用資料則返回 None

此外,read() 方法沒有一個委託給 readinto() 的預設實現。

一個典型的 BufferedIOBase 實現不應該繼承自 RawIOBase 實現,而是包裝一個,就像 BufferedWriterBufferedReader 所做的那樣。

BufferedIOBase 除了從 IOBase 繼承的屬性和方法外,還提供或覆蓋了以下內容:

raw

BufferedIOBase 處理的底層原始流(一個 RawIOBase 例項)。這不屬於 BufferedIOBase API 的一部分,並且在某些實現中可能不存在。

detach()

將底層原始流從緩衝區中分離出來並返回它。

在原始流被分離後,緩衝區處於不可用狀態。

一些緩衝區,如 BytesIO,沒有單一原始流的概念可從此方法返回。它們會引發 UnsupportedOperation

在 3.1 版本加入。

read(size=-1, /)

讀取並返回最多 size 個位元組。如果引數省略、為 None 或為負數,則儘可能多地讀取。

返回的位元組數可能少於請求的數量。如果流已經到達 EOF,則返回一個空的 bytes 物件。可能會進行多次讀取,並且在遇到特定錯誤時可能會重試呼叫,更多細節請參閱 os.read()PEP 475。返回的位元組數少於 size 並不意味著即將到達 EOF。

當儘可能多地讀取時,如果可用,預設實現將使用 raw.readall(它應該實現 RawIOBase.readall()),否則將迴圈讀取,直到 read 返回 None、一個空的 bytes 或一個不可重試的錯誤。對於大多數流來說,這是到 EOF,但對於非阻塞流,可能會有更多資料可用。

備註

當底層原始流是非阻塞時,實現可能會在沒有可用資料時引發 BlockingIOError 或返回 Noneio 實現返回 None

read1(size=-1, /)

讀取並返回最多 size 個位元組,呼叫 readinto(),根據 PEP 475 的規定,如果遇到 EINTR 可能會重試。如果 size-1 或未提供,實現將為 size 選擇一個任意值。

備註

當底層原始流是非阻塞時,實現可能會在沒有可用資料時引發 BlockingIOError 或返回 Noneio 實現返回 None

readinto(b, /)

將位元組讀入一個預先分配的可寫的類位元組物件 b 中,並返回讀取的位元組數。例如,b 可能是一個 bytearray

read() 類似,可能會對底層原始流發出多次讀取,除非後者是互動式的。

如果底層原始流處於非阻塞模式,並且當前沒有可用資料,則會引發 BlockingIOError

readinto1(b, /)

將位元組讀入預先分配的可寫的類位元組物件 b 中,最多隻呼叫一次底層原始流的 read()(或 readinto())方法。返回讀取的位元組數。

如果底層原始流處於非阻塞模式,並且當前沒有可用資料,則會引發 BlockingIOError

在 3.5 版本加入。

write(b, /)

寫入給定的類位元組物件 b,並返回寫入的位元組數(總是等於 b 的位元組長度,因為如果寫入失敗將引發 OSError)。根據實際實現,這些位元組可能會立即寫入底層流,或者為了效能和延遲原因而儲存在緩衝區中。

在非阻塞模式下,如果需要寫入的資料無法被原始流在不阻塞的情況下全部接受,則會引發 BlockingIOError

呼叫者在此方法返回後可以釋放或修改 b,因此實現應僅在方法呼叫期間訪問 b

原始檔案 I/O

class io.FileIO(name, mode='r', closefd=True, opener=None)

一個原始二進位制流,表示一個包含位元組資料的作業系統級檔案。它繼承自 RawIOBase

name 可以是以下兩種之一:

  • 一個表示將要開啟的檔案路徑的字串或 bytes 物件。在這種情況下,closefd 必須為 True(預設值),否則將引發錯誤。

  • 一個整數,表示現有作業系統級檔案描述符的編號,生成的 FileIO 物件將給予對此的訪問許可權。當 FileIO 物件關閉時,此檔案描述符也將被關閉,除非 closefd 設定為 False

mode 可以是 'r', 'w', 'x''a',分別用於讀取(預設)、寫入、獨佔建立或追加。當以寫入或追加模式開啟時,如果檔案不存在則會建立檔案;以寫入模式開啟時,檔案將被截斷。當以建立模式開啟時,如果檔案已存在,將引發 FileExistsError。以建立模式開啟檔案意味著寫入,因此此模式的行為類似於 'w'。在模式中新增 '+' 以允許同時讀寫。

此類上的 read()(當用正數引數呼叫時)、readinto()write() 方法只會進行一次系統呼叫。

可以透過傳遞一個可呼叫物件作為 opener 來使用自定義開啟器。然後透過呼叫 opener 並傳入 (name, flags) 來獲取檔案物件的底層檔案描述符。opener 必須返回一個開啟的檔案描述符(將 os.open 作為 opener 傳遞的結果類似於傳遞 None)。

新建立的檔案是不可繼承的

有關使用 opener 引數的示例,請參見內建函式 open()

在 3.3 版更改: 增加了 opener 引數。增加了 'x' 模式。

在 3.4 版更改: 檔案現在是不可繼承的。

FileIO 除了 RawIOBaseIOBase 的屬性外,還提供了這些資料屬性:

mode

建構函式中給定的模式。

name

檔名。如果在建構函式中沒有給出名稱,則這是檔案的檔案描述符。

緩衝流

緩衝 I/O 流提供了比原始 I/O 更高級別的 I/O 裝置介面。

class io.BytesIO(initial_bytes=b'')

一個使用記憶體中位元組緩衝區的二進位制流。它繼承自 BufferedIOBase。當呼叫 close() 方法時,緩衝區將被丟棄。

可選引數 initial_bytes 是一個包含初始資料的類位元組物件

BytesIO 除了從 BufferedIOBaseIOBase 繼承的方法外,還提供或覆蓋了這些方法:

getbuffer()

返回一個對緩衝區內容的可讀寫檢視,而無需複製它們。此外,修改檢視將透明地更新緩衝區的內容:

>>> b = io.BytesIO(b"abcdef")
>>> view = b.getbuffer()
>>> view[2:4] = b"56"
>>> b.getvalue()
b'ab56ef'

備註

只要該檢視存在,BytesIO 物件就不能被調整大小或關閉。

在 3.2 版本加入。

getvalue()

返回一個包含緩衝區全部內容的 bytes 物件。

read1(size=-1, /)

BytesIO 中,這與 read() 相同。

在 3.7 版更改: size 引數現在是可選的。

readinto1(b, /)

BytesIO 中,這與 readinto() 相同。

在 3.5 版本加入。

class io.BufferedReader(raw, buffer_size=DEFAULT_BUFFER_SIZE)

一個緩衝二進位制流,為可讀、不可查詢的 RawIOBase 原始二進位制流提供更高級別的訪問。它繼承自 BufferedIOBase

當從此物件讀取資料時,可能會從底層原始流請求更大量的資料,並儲存在內部緩衝區中。然後,緩衝的資料可以在後續讀取中直接返回。

建構函式為給定的可讀 raw 流和 buffer_size 建立一個 BufferedReader。如果省略 buffer_size,則使用 DEFAULT_BUFFER_SIZE

BufferedReader 除了從 BufferedIOBaseIOBase 繼承的方法外,還提供或覆蓋了這些方法:

peek(size=0, /)

從流中返回位元組,但不移動檔案指標。返回的位元組數可能比請求的要少或多。如果底層的原始流是非阻塞的,並且操作會阻塞,則返回空位元組。

read(size=-1, /)

BufferedReader 中,這與 io.BufferedIOBase.read() 相同。

read1(size=-1, /)

BufferedReader 中,這與 io.BufferedIOBase.read1() 相同。

在 3.7 版更改: size 引數現在是可選的。

class io.BufferedWriter(raw, buffer_size=DEFAULT_BUFFER_SIZE)

一個帶緩衝的二進位制流,為可寫的、不可查詢的 RawIOBase 原始二進位制流提供了更高級別的訪問。它繼承自 BufferedIOBase

當向此物件寫入時,資料通常會放入一個內部緩衝區。在各種情況下,緩衝區將被寫出到底層的 RawIOBase 物件中,包括:

建構函式為給定的可寫 raw 流建立一個 BufferedWriter。如果未指定 buffer_size,則預設為 DEFAULT_BUFFER_SIZE

BufferedWriterBufferedIOBaseIOBase 的方法之外,還提供或重寫了以下方法:

flush()

強制將緩衝區中保留的位元組寫入原始流。如果原始流阻塞,則應引發 BlockingIOError

write(b, /)

寫入 類位元組物件 b,並返回寫入的位元組數。在非阻塞模式下,如果緩衝區需要寫出但原始流阻塞,則會引發 BlockingIOError,並設定其 BlockingIOError.characters_written 屬性。

class io.BufferedRandom(raw, buffer_size=DEFAULT_BUFFER_SIZE)

一個帶緩衝的二進位制流,為可查詢的 RawIOBase 原始二進位制流提供了更高級別的訪問。它繼承自 BufferedReaderBufferedWriter

建構函式為第一個引數中給定的可查詢原始流建立一個讀取器和寫入器。如果省略了 buffer_size,則預設為 DEFAULT_BUFFER_SIZE

BufferedRandom 能夠完成 BufferedReaderBufferedWriter 所能做的一切。此外,保證實現了 seek()tell()

class io.BufferedRWPair(reader, writer, buffer_size=DEFAULT_BUFFER_SIZE, /)

一個帶緩衝的二進位制流,為兩個不可查詢的 RawIOBase 原始二進位制流(一個可讀,另一個可寫)提供了更高級別的訪問。它繼承自 BufferedIOBase

readerwriter 是分別是可讀和可寫的 RawIOBase 物件。如果省略了 buffer_size,則預設為 DEFAULT_BUFFER_SIZE

BufferedRWPair 實現了 BufferedIOBase 的所有方法,除了 detach() 會引發 UnsupportedOperation

警告

BufferedRWPair 不會嘗試同步對其底層原始流的訪問。你不應該將同一個物件同時作為讀取器和寫入器傳遞給它;應改用 BufferedRandom

文字 I/O

class io.TextIOBase

文字流的基類。此類為流 I/O 提供了基於字元和行的介面。它繼承自 IOBase

TextIOBaseIOBase 的基礎上提供或重寫了以下資料屬性和方法:

encoding

用於將流的位元組解碼為字串,以及將字串編碼為位元組的編碼名稱。

errors

解碼器或編碼器的錯誤設定。

newlines

一個字串、一個字串元組或 None,表示迄今為止已轉換的換行符。根據實現和初始建構函式標誌,此屬性可能不可用。

buffer

TextIOBase 處理的底層二進位制緩衝區(一個 BufferedIOBaseRawIOBase 例項)。這不是 TextIOBase API 的一部分,並且在某些實現中可能不存在。

detach()

將底層二進位制緩衝區與 TextIOBase 分離並返回它。

底層緩衝區被分離後,TextIOBase 處於不可用狀態。

一些 TextIOBase 的實現,如 StringIO,可能沒有底層緩衝區的概念,呼叫此方法將引發 UnsupportedOperation

在 3.1 版本加入。

read(size=-1, /)

從流中讀取並返回最多 size 個字元作為一個 str。如果 size 為負數或 None,則讀取直到檔案結束符(EOF)。

readline(size=-1, /)

讀取直到換行符或 EOF,並返回一個 str。如果流已處於 EOF,則返回一個空字串。

如果指定了 size,最多將讀取 size 個字元。

seek(offset, whence=SEEK_SET, /)

將流位置更改為給定的 offset。行為取決於 whence 引數。whence 的預設值為 SEEK_SET

  • SEEK_SET0:從流的開頭開始查詢(預設值);offset 必須是由 TextIOBase.tell() 返回的數字,或者為零。任何其他的 offset 值都會產生未定義的行為。

  • SEEK_CUR1:“查詢”到當前位置;offset 必須為零,這是一個無操作(所有其他值都不支援)。

  • SEEK_END2:查詢到流的末尾;offset 必須為零(所有其他值都不支援)。

以一個不透明的數字形式返回新的絕對位置。

在 3.1 版新加入: SEEK_* 常量。

tell()

以一個不透明的數字形式返回當前流的位置。該數字通常不表示底層二進位制儲存中的位元組數。

write(s, /)

將字串 s 寫入流中,並返回寫入的字元數。

class io.TextIOWrapper(buffer, encoding=None, errors=None, newline=None, line_buffering=False, write_through=False)

一個帶緩衝的文字流,為 BufferedIOBase 緩衝二進位制流提供了更高級別的訪問。它繼承自 TextIOBase

encoding 給出了流將被解碼或編碼的編碼名稱。在 UTF-8 模式下,預設為 UTF-8。否則,預設為 locale.getencoding()。可以使用 encoding="locale" 來顯式指定當前區域的編碼。更多資訊請參見 文字編碼

errors 是一個可選字串,用於指定如何處理編碼和解碼錯誤。傳遞 'strict' 以在出現編碼錯誤時引發 ValueError 異常(預設的 None 具有相同的效果),或傳遞 'ignore' 來忽略錯誤。(注意,忽略編碼錯誤可能導致資料丟失。)'replace' 會在格式錯誤的資料處插入一個替換標記(如 '?')。'backslashreplace' 會將格式錯誤的資料替換為反斜槓轉義序列。在寫入時,可以使用 'xmlcharrefreplace'(替換為適當的 XML 字元引用)或 'namereplace'(替換為 \N{...} 轉義序列)。任何已透過 codecs.register_error() 註冊的其他錯誤處理名稱也是有效的。

newline 控制如何處理行尾。它可以是 None'''\n''\r''\r\n'。它的工作方式如下:

  • 從流中讀取輸入時,如果 newlineNone,則啟用通用換行模式。輸入中的行可以以 '\n''\r''\r\n' 結尾,這些都會在返回給呼叫者之前被翻譯成 '\n'。如果 newline'',則啟用通用換行模式,但行尾會未經翻譯地返回給呼叫者。如果 newline 是任何其他合法值,輸入行僅由給定的字串終止,並且行尾會未經翻譯地返回給呼叫者。

  • 向流中寫入輸出時,如果 newlineNone,則任何寫入的 '\n' 字元都將被翻譯成系統預設的行分隔符 os.linesep。如果 newline'''\n',則不進行翻譯。如果 newline 是任何其他合法值,則任何寫入的 '\n' 字元都將被翻譯成給定的字串。

如果 line_bufferingTrue,則當對 write 的呼叫包含換行符或回車符時,會隱式呼叫 flush()

如果 write_throughTrue,則對 write() 的呼叫保證不會被緩衝:任何寫入 TextIOWrapper 物件的資料都會立即傳遞給其底層的二進位制 buffer

在 3.3 版更改: 增加了 write_through 引數。

在 3.3 版更改: 預設的 encoding 現在是 locale.getpreferredencoding(False) 而不是 locale.getpreferredencoding()。不要使用 locale.setlocale() 臨時更改區域編碼,應使用當前區域編碼而不是使用者首選的編碼。

在 3.10 版更改: encoding 引數現在支援 "locale" 這個偽編碼名稱。

備註

當底層原始流是非阻塞時,如果讀取操作無法立即完成,可能會引發 BlockingIOError

TextIOWrapperTextIOBaseIOBase 的基礎上提供了以下資料屬性和方法:

line_buffering

行緩衝是否啟用。

write_through

寫入操作是否立即傳遞給底層二進位制緩衝區。

在 3.7 版本加入。

reconfigure(*, encoding=None, errors=None, newline=None, line_buffering=None, write_through=None)

使用新的 encodingerrorsnewlineline_bufferingwrite_through 設定重新配置此文字流。

未指定的引數將保持當前設定,但如果指定了 encoding 而未指定 errors,則使用 errors='strict'

如果已經從流中讀取了資料,則無法更改編碼或換行符。另一方面,在寫入後更改編碼是可能的。

此方法在設定新引數之前會隱式地重新整理流。

在 3.7 版本加入。

在 3.11 版更改: 該方法支援 encoding="locale" 選項。

seek(cookie, whence=os.SEEK_SET, /)

設定流的位置。以 int 形式返回新的流位置。

支援以下引數組合的四種操作:

  • seek(0, SEEK_SET):倒回到流的開頭。

  • seek(cookie, SEEK_SET):恢復到之前的位置;cookie 必須是tell() 返回的數字。

  • seek(0, SEEK_END):快進到流的末尾。

  • seek(0, SEEK_CUR):保持當前流位置不變。

任何其他引數組合都是無效的,可能會引發異常。

tell()

以一個不透明的數字形式返回流的位置。tell() 的返回值可以作為 seek() 的輸入,以恢復之前的流位置。

class io.StringIO(initial_value='', newline='\n')

使用記憶體中文字緩衝區的文字流。它繼承自 TextIOBase

當呼叫 close() 方法時,文字緩衝區將被丟棄。

可以透過提供 initial_value 來設定緩衝區的初始值。如果啟用了換行符轉換,換行符將像透過 write() 一樣進行編碼。流的位置被設定在緩衝區的開頭,這模擬了以 w+ 模式開啟現有檔案,使其準備好從頭開始立即寫入或覆蓋初始值。要模擬以 a+ 模式開啟檔案準備追加,請使用 f.seek(0, io.SEEK_END) 將流重新定位到緩衝區的末尾。

newline 引數的工作方式與 TextIOWrapper 類似,但在向流中寫入輸出時,如果 newlineNone,則在所有平臺上換行符都寫為 \n

StringIOTextIOBaseIOBase 的基礎上提供了以下方法:

getvalue()

返回一個包含緩衝區全部內容的 str。換行符的解碼方式與 read() 類似,但流的位置不會改變。

用法示例:

import io

output = io.StringIO()
output.write('First line.\n')
print('Second line.', file=output)

# Retrieve file contents -- this will be
# 'First line.\nSecond line.\n'
contents = output.getvalue()

# Close object and discard memory buffer --
# .getvalue() will now raise an exception.
output.close()
class io.IncrementalNewlineDecoder

一個輔助編解碼器,用於在通用換行模式下解碼換行符。它繼承自 codecs.IncrementalDecoder

靜態型別

以下協議可用於為簡單的流讀取或寫入操作的函式和方法引數添加註解。它們都使用了 @typing.runtime_checkable 裝飾器。

class io.Reader[T]

用於從檔案或其他輸入流讀取的通用協議。T 通常是 strbytes,但也可以是從流中讀取的任何型別。

在 3.14 版本加入。

read()
read(size, /)

從輸入流中讀取資料並返回。如果指定了 size,它應該是一個整數,並且最多會讀取 size 個專案(位元組/字元)。

例如:

def read_it(reader: Reader[str]):
    data = reader.read(11)
    assert isinstance(data, str)
class io.Writer[T]

用於向檔案或其他輸出流寫入的通用協議。T 通常是 strbytes,但也可以是任何可以寫入流中的型別。

在 3.14 版本加入。

write(data, /)

data 寫入輸出流,並返回寫入的專案數(位元組/字元)。

例如:

def write_binary(writer: Writer[bytes]):
    writer.write(b"Hello world!\n")

有關可用於靜態型別檢查的其他 I/O 相關協議和類,請參閱 用於處理 I/O 的 ABC 和協議

效能

本節討論了提供的具體 I/O 實現的效能。

二進位制 I/O

透過即使在使用者請求單個位元組時也只讀寫大塊資料,緩衝 I/O 隱藏了呼叫和執行作業系統無緩衝 I/O 例程的任何低效。其增益取決於作業系統和執行的 I/O 型別。例如,在一些現代作業系統(如 Linux)上,無緩衝磁碟 I/O 可以與緩衝 I/O 一樣快。然而,最重要的是,無論平臺和後備裝置如何,緩衝 I/O 都能提供可預測的效能。因此,對於二進位制資料,幾乎總是優先使用緩衝 I/O 而不是無緩衝 I/O。

文字 I/O

在二進位制儲存(如檔案)上的文字 I/O 比在相同儲存上的二進位制 I/O 慢得多,因為它需要使用字元編解碼器在 Unicode 和二進位制資料之間進行轉換。這在處理大量文字資料(如大型日誌檔案)時會變得很明顯。此外,由於使用了重構演算法,tell()seek() 都相當慢。

然而,StringIO 是一個原生的記憶體中 Unicode 容器,其速度與 BytesIO 相似。

多執行緒

FileIO 物件是執行緒安全的,前提是它們所包裝的作業系統呼叫(例如在 Unix 下的 read(2))也是執行緒安全的。

二進位制緩衝物件(BufferedReaderBufferedWriterBufferedRandomBufferedRWPair 的例項)使用鎖來保護其內部結構;因此,可以安全地從多個執行緒同時呼叫它們。

TextIOWrapper 物件不是執行緒安全的。

可重入性

二進位制緩衝物件(BufferedReaderBufferedWriterBufferedRandomBufferedRWPair 的例項)是不可重入的。雖然在正常情況下不會發生可重入呼叫,但在 signal 處理程式中進行 I/O 操作時可能會出現。如果一個執行緒試圖重新進入它已經在訪問的緩衝物件,會引發 RuntimeError。注意,這並不禁止另一個執行緒進入該緩衝物件。

以上內容也隱式地擴充套件到文字檔案,因為 open() 函式會將一個緩衝物件包裝在 TextIOWrapper 內部。這包括標準流,因此也影響了內建的 print() 函式。