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