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() 方法,也會引發同樣的錯誤。
文字 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 文件中有詳細描述。
文字編碼¶
TextIOWrapper 和 open() 預設編碼是根據區域設定的 (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()的別名。此函式會引發一個帶有引數 path、mode 以及 flags 的稽核事件 (auditing event)
open。mode 與 flags 引數可能已經被修改或者從原始呼叫中被推斷出來。
- 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為真,且 encoding 為None,此函式會發出一個EncodingWarning。stacklevel 指定警告在哪層發出。範例: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 模式啟用且 encoding 為
None時,text_encoding()會回傳 "utf-8"。
- exception io.BlockingIOError¶
這是內建的
BlockingIOError例外的相容性別名。
- exception io.UnsupportedOperation¶
當在資料串流上呼叫不支援的操作時,會引發繼承自
OSError與ValueError的例外。
也參考
sys包含標準的 IO 資料串流:
sys.stdin、sys.stdout以及sys.stderr。
類別階層¶
I/O 串流的實作是由多個類別組合成的階層結構所構成。首先是 abstract base classes (抽象基底類別,ABCs),它們被用來規範各種不同類型的串流,接著具體類別會提供標準串流的實作。
備註
為了協助具體串流類別的實作,抽象基底類別提供了某些方法的預設實作。舉例來說,BufferedIOBase 提供未經最佳化的 readinto() 與 readline() 實作。
I/O 階層結構的最上層是抽象基底類別 IOBase。它定義了串流的基礎的介面。然而,請注意,讀取串流與寫入串流之間並沒有分離;若不支援給定的操作,實作是允許引發 UnsupportedOperation 例外的。
抽象基底類別 RawIOBase 繼承 IOBase。此類別處理對串流的位元組讀寫。FileIO 則繼承 RawIOBase 來提供一個介面以存取機器檔案系統內的檔案。
抽象基底類別 BufferedIOBase 繼承 IOBase。此類別緩衝原始二進位串流 (RawIOBase)。它的子類別 BufferedWriter、BufferedReader 與 BufferedRWPair 分別緩衝可寫、可讀、可讀也可寫的的原始二進位串流。類別 BufferedRandom 則提供一個對可搜尋串流 (seekable stream) 的緩衝介面。另一個類別 BufferedIOBase 的子類別 BytesIO,是一個記憶體內位元組串流。
抽象基底類別 TextIOBase 繼承 IOBase。此類別處理文本位元組串流,並處理字串的編碼和解碼。類別 TextIOWrapper 繼承自 TextIOBase,這是個對緩衝原始串流 (BufferedIOBase) 的緩衝文本介面。最後,StringIO 是個文字記憶體內串流。
引數名稱不是規範的一部份,只有 open() 的引數將作為關鍵字引數。
以下表格總結了 io 模組提供的抽象基底類別 (ABC):
抽象基底類別 (ABC) |
繼承 |
Stub 方法 |
Mixin 方法與屬性 |
|---|---|---|---|
|
|
||
|
繼承自 |
||
|
繼承自 |
||
|
繼承自 |
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 withstrdata.請注意,在一個已經關閉的串流上呼叫任何方法(即使只是查詢)都是未定義的。在這種情況下,實作可能會引發
ValueError例外。IOBase(and its subclasses) supports the iterator protocol, meaning that anIOBaseobject 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). Seereadline()below.IOBase也是個情境管理器,因此支援with陳述式。在這個例子中,file 會在with陳述式執行完畢後關閉——即使發生了異常。with open('spam.txt', 'w') as file: file.write('Spam and eggs!')
IOBase提供這些資料屬性與方法:- close()¶
清除並關閉這個串流。若檔案已經關閉,則此方法沒有作用。一旦檔案被關閉,任何對檔案的操作(例如讀取或寫入)將引發
ValueError異常。為了方便起見,允許多次呼叫這個方法;然而,只有第一次呼叫會有效果。
- closed¶
如果串流已關閉,則為
True。
- flush()¶
如果適用,清空串流的寫入緩衝區。對於唯讀和非阻塞串流,此操作不會執行任何操作。
- isatty()¶
如果串流是互動式的(即連接到終端機/tty 設備),則回傳
True。
- 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_SET或0-- 串流的起點(預設值);offset 應為零或正數os.SEEK_CUR或1-- 目前串流位置;offset 可以是負數os.SEEK_END或2-- 串流的結尾;offset 通常是負數
在 3.1 版被加入:
SEEK_*常數。在 3.3 版被加入: 某些作業系統可以支援額外的值,例如
os.SEEK_HOLE或os.SEEK_DATA。檔案的合法值取決於它是以文字模式還是二進位模式開啟。
- seekable()¶
如果串流支援隨機存取,則回傳
True。如果是False,則seek()、tell()和truncate()會引發OSError。
- tell()