io — 處理資料串流的核心工具

原始碼:Lib/io.py


總覽

io 模組替 Python 提供處理各種類型 IO 的主要工具。有三種主要的 IO 類型: 文字 I/O (text I/O)二進位 I/O (binary I/O) 以及原始 I/O (raw I/O)。這些均為泛用 (generic) 類型,且每種類型都可以使用各式後端儲存 (backing store)。任一種屬於這些類型的具體物件稱為 file object。其它常見的名詞還有資料串流 (stream) 以及類檔案物件 (file-like objects)

無論其類型為何,每個具體的資料串流物件也將具有各種能力:唯讀的、只接受寫入的、或者讀寫兼具的。它還允許任意的隨機存取(向前或向後尋找至任意位置),或者只能依順序存取(例如 socket 或 pipe 的情形下)。

所有的資料串流都會謹慎處理你所提供的資料的型別。舉例來說,提供一個 str 物件給二進位資料串流的 write() 方法將會引發 TypeError。同樣地,若提供一個 bytes 物件給文字資料串流的 write() 方法,也會引發同樣的錯誤。

在 3.3 版的變更: 原本會引發 IOError 的操作,現在將改成引發 OSError。因為 IOError 現在是 OSError 的別名。

文字 I/O

文字 I/O 要求和產出 str 物件。這意味著每當後端儲存為原生 bytes 時(例如在檔案的情形下),資料的編碼與解碼會以清楚易懂的方式進行,也可選擇同時轉換特定於平台的換行字元。

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

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

記憶體內的文字資料串流也可以使用 StringIO 物件建立:

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

備註

When working with a non-blocking stream, be aware that read operations on text I/O objects might raise a BlockingIOError if the stream cannot perform the operation immediately.

文字資料串流 API 的詳細說明在 TextIOBase 文件當中。

二進位 (Binary) I/O

二進位 I/O(也稱為緩衝 I/O (buffered I/O))要求的是類位元組物件 (bytes-like objects) 且產生 bytes 物件。不進行編碼、解碼或者換行字元轉換。這種類型的資料串流可用於各種非文字資料,以及需要手動控制對文字資料的處理時。

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

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

記憶體內的二進位資料串流也可以透過 BytesIO 物件來建立:

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

二進位資料串流 API 的詳細說明在 BufferedIOBase 文件當中。

其它函式庫模組可能提供額外的方法來建立文字或二進位資料串流。例如 socket.socket.makefile()

原始 (Raw) I/O

原始 I/O(也稱為無緩衝 I/O (unbuffered I/O))通常作為二進位以及文字資料串流的低階 building-block 使用;在使用者程式碼中直接操作原始資料串流很少有用。然而,你可以透過以無緩衝的二進位模式開啟一個檔案來建立一個原始資料串流:

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

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

文字編碼

TextIOWrapperopen() 預設編碼是根據區域設定的 (locale-specific) (locale.getencoding())。

然而,許多開發人員在開啟以 UTF-8 編碼的文字檔案(例如:JSON、TOML、Markdown等)時忘記指定編碼,因為多數 Unix 平台預設使用 UTF-8 區域設定。這會導致錯誤,因為對於大多數 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 模式

選擇性加入的編碼警告

在 3.10 版被加入: 更多資訊請見 PEP 597

要找出哪些地方使用到預設的地區編碼,你可以啟用 -X warn_default_encoding 命令列選項,或者設定環境變數 PYTHONWARNDEFAULTENCODING。當使用到預設編碼時,會引發 EncodingWarning

如果你正在提供一個使用 open()TextIOWrapper 且傳遞 encoding=None 作為參數的 API,你可以使用 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() 的別名。

此函式會引發一個帶有引數 pathmode 以及 flags稽核事件 (auditing event) openmodeflags 引數可能已經被修改或者從原始呼叫中被推斷出來。

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 Mode 回傳 "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.stdout 以及 sys.stderr

類別階層

I/O 串流的實作是由多個類別組合成的階層結構所構成。首先是 abstract base classes (抽象基底類別,ABCs),它們被用來規範各種不同類型的串流,接著具體類別會提供標準串流的實作。

備註

為了協助具體串流類別的實作,抽象基底類別提供了某些方法的預設實作。舉例來說,BufferedIOBase 提供未經最佳化的 readinto()readline() 實作。

I/O 階層結構的最上層是抽象基底類別 IOBase。它定義了串流的基礎的介面。然而,請注意,讀取串流與寫入串流之間並沒有分離;若不支援給定的操作,實作是允許引發 UnsupportedOperation 例外的。

抽象基底類別 RawIOBase 繼承 IOBase。此類別處理對串流的位元組讀寫。FileIO 則繼承 RawIOBase 來提供一個介面以存取機器檔案系統內的檔案。

抽象基底類別 BufferedIOBase 繼承 IOBase。此類別緩衝原始二進位串流 (RawIOBase)。它的子類別 BufferedWriterBufferedReaderBufferedRWPair 分別緩衝可寫、可讀、可讀也可寫的的原始二進位串流。類別 BufferedRandom 則提供一個對可搜尋串流 (seekable stream) 的緩衝介面。另一個類別 BufferedIOBase 的子類別 BytesIO,是一個記憶體內位元組串流。

抽象基底類別 TextIOBase 繼承 IOBase。此類別處理文本位元組串流,並處理字串的編碼和解碼。類別 TextIOWrapper 繼承自 TextIOBase,這是個對緩衝原始串流 (BufferedIOBase) 的緩衝文本介面。最後,StringIO 是個文字記憶體內串流。

引數名稱不是規範的一部份,只有 open() 的引數將作為關鍵字引數。

以下表格總結了 io 模組提供的抽象基底類別 (ABC):

抽象基底類別 (ABC)

繼承

Stub 方法

Mixin 方法與屬性

IOBase

filenoseektruncate

closeclosed__enter____exit__flushisatty__iter____next__readablereadlinereadlinesseekabletellwritablewritelines

RawIOBase

IOBase

readintowrite

繼承自 IOBase 的方法,readreadall

BufferedIOBase

IOBase

detachreadread1write

繼承自 IOBase 的方法,readintoreadinto1

TextIOBase

IOBase

detachreadreadlinewrite

繼承自 IOBase 的方法,encodingerrorsnewlines

I/O 基礎類別

class io.IOBase

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

為許多方法提供了空的抽象實作,衍生類別可以選擇性地覆寫這些方法;預設的實作代表一個無法讀取、寫入或搜尋的檔案。

即使 IOBase 因為實作的簽名差異巨大而沒有宣告 read()write() 方法,實作與用戶端應把這些方法視為介面的一部份。此外,當呼叫不被它們支援的操作時,可能會引發 ValueError (或 UnsupportedOperation)例外。

The basic type used for binary data read from or written to a file is bytes. Other bytes-like objects are accepted as method arguments too. Text I/O classes work with str data.

請注意,在一個已經關閉的串流上呼叫任何方法(即使只是查詢)都是未定義的。在這種情況下,實作可能會引發 ValueError 例外。

IOBase (and its subclasses) supports the iterator protocol, meaning that an IOBase object can be iterated over yielding the lines in a stream. Lines are defined slightly differently depending on whether the stream is a binary stream (yielding bytes), or a text stream (yielding character strings). See readline() below.

IOBase 也是個情境管理器,因此支援 with 陳述式。在這個例子中,file 會在 with 陳述式執行完畢後關閉——即使發生了異常。

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, /)

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

hint 值為 0 或更小,以及 None,都被視為沒有提供 hint。

請注意,已經可以使用 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。如果是 False,則 seek()tell()truncate() 會引發 OSError

tell()

回傳目前串流的位置。

truncate(size=None, /)

將串流的大小調整為指定的 size 位元組(如果沒有指定 size,則調整為目前位置)。目前串流位置不會改變。這種調整可以擴展或縮減目前檔案大小。在擴展的情況下,新檔案區域的內容取決於平台(在大多數系統上,額外的位元組會被填充為零)。回傳新的檔案大小。

在 3.5 版的變更: Windows 現在在擴展時會對檔案進行零填充 (zero-fill)。

writable()

如果串流支援寫入,則回傳 True。如果是 Falsewrite()truncate() 將會引發 OSError

writelines(lines, /)

將一個包含每一行的 list 寫入串流。這不會新增行分隔符號,因此通常提供的每一行末尾都有一個行分隔符號。

__del__()

為物件銷毀做準備。IOBase 提供了這個方法的預設實作,該實作會呼叫實例的 close() 方法。

class io.RawIOBase

原始二進位串流的基底類別。它繼承自 IOBase

原始二進位串流通常提供對底層作業系統設備或 API 的低階存取,並不嘗試將其封裝在高階原語 (primitive) 中(這項功能在緩衝二進位串流和文字串流中的更高階層級完成,後面的頁面會有描述)。

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

read(size=-1,