io --- 輸入/輸出串流¶
本模組包含其他類型的 stream(類檔案)物件以及輔助函式。它公開了內建的 open() 函式,並提供記憶體中的文字與二進位緩衝區(StringIO、BytesIO),這些緩衝區實作了標準的 read/write/seek 串流介面。
概念階層¶
與 CPython 的差異
串流基底類別的概念階層在 MicroPython 中經過簡化,如本節所述。
(抽象)基底串流類別作為所有具體類別行為的基礎,在 CPython 中遵循少數幾項二分法(成對分類)。在 MicroPython 中,這些分類經過某種程度的簡化,並隱含於實作之中,以達到更高的效率並節省資源。
CPython 中一項重要的二分法是無緩衝串流與有緩衝串流。在 MicroPython 中,目前所有串流皆為無緩衝。這是因為所有現代作業系統,甚至許多 RTOS 與檔案系統驅動程式都已在其端進行緩衝。再加入一層緩衝會適得其反(這個問題稱為「緩衝膨脹」),且會佔用寶貴的記憶體。請注意,在某些情況下緩衝仍可能有用,因此我們日後可能會引入選用的緩衝支援。
但在 CPython 中,另一項重要的二分法與「是否有緩衝」息息相關——即串流是否可能發生短讀/短寫。所謂短讀,是指使用者向串流要求例如 10 個位元組,卻得到較少的位元組;短寫亦同理。在 CPython 中,無緩衝串流會自動容易發生短操作,而有緩衝串流則保證不會發生。不發生短讀/短寫是一項重要特性,因為它能讓開發者撰寫更精簡且高效的程式——這正是 MicroPython 高度期望的目標。因此,雖然 MicroPython 不支援有緩衝串流,但它仍提供不發生短操作的串流。是否會發生短操作取決於每個特定類別的需求,但強烈建議開發者基於上述理由優先採用不發生短操作的行為。例如,MicroPython 的 socket 保證避免短讀/短寫。實際上目前核心中並沒有短操作串流類別的範例,而這類類別會是特定於某種硬體的。
在非阻塞串流的情況下,不發生短操作的行為會變得棘手;阻塞與非阻塞行為是 CPython 的另一項二分法,且 MicroPython 完全支援。非阻塞串流絕不會等待資料抵達或寫入——它們會盡可能讀取/寫入,或在缺乏資料(或無法寫入資料)時發出訊號。顯然這與「不發生短操作」的原則相衝突,事實上,非阻塞且有緩衝(亦即不發生短操作)串流的情況在 CPython 中相當複雜——有些地方禁止這種組合,有些地方則行為未定義或單純未加說明,某些情況下還會擲出冗長的例外。這件事在 MicroPython 中簡單得多:非阻塞串流對於高效的非同步操作至關重要,因此此特性優先於「不發生短操作」特性。所以,雖然阻塞串流會盡可能避免短讀/短寫(唯一會發生短讀的情況是抵達檔案結尾,或發生錯誤時(但錯誤不會回傳短資料,而是擲出例外)),非阻塞串流則可能產生短資料以避免阻塞該操作。
最後一項二分法是二進位串流與文字串流。MicroPython 當然支援這兩者,但在 CPython 中文字串流本質上是有緩衝的,在 MicroPython 中則並非如此。(事實上,這正是我們可能引入緩衝支援的情況之一。)
請注意,為了效率,MicroPython 並未提供對應於上述階層的抽象基底類別,而且無法在純 Python 中實作或繼承串流類別。
函式¶
類別¶
- class io.IOBase¶
串流(「類檔案」)物件的基底類別。具體的子類別會實作下方的低階 I/O 方法(
readinto、write、ioctl);執行階段會在其上建構較高階的串流協定(read、readline、readlines、close、迭代),因此即使子類別未定義這些方法,每個串流實例也都支援它們。實作方法(在子類別中覆寫這些方法):
- readinto(buf: bytearray) int | None¶
將位元組讀入可寫入的緩衝區 buf。回傳讀取的位元組數、在串流結尾時回傳
0,若目前沒有可用資料則回傳None(適用於非阻塞串流)。
- ioctl(request: int, arg: int) int¶
控制底層的串流/裝置。request 是
MP_STREAM_*請求碼之一。成功時回傳非負值,發生錯誤時回傳負的errno值。
串流協定方法(可用於每個串流實例):
- read(size: int = -1)¶
讀取並回傳最多 size 個位元組(在文字模式下則為字元)。若省略 size 或為負值,則讀取至串流結尾。二進位串流回傳
bytes,文字串流回傳str;空的結果表示串流結尾。
- readline(size: int = -1)¶
讀取並回傳一行,若存在則包含尾端的換行字元。若有指定 size,則最多讀取 size 個位元組(或字元)。在串流結尾時回傳空的
bytes/str。
- close() None¶
關閉串流並釋放任何底層資源。對已關閉的串流進行操作會擲出
OSError(記憶體中串流則擲出ValueError)。
- seek(offset: int, whence: int = 0) int¶
將目前的串流位置變更為相對於 whence 的 offset 位元組(
0= 串流起點,1= 目前位置,2= 串流結尾)。回傳新的絕對位置。在無法尋址的串流上會擲出OSError。
直接迭代串流時,每次迭代會產生一行——等同於在迴圈中呼叫
readline(),直到回傳代表串流結尾的空行哨符為止。串流也支援情境管理器協定,因此with open(...) as f:會自動關閉串流。備註
MicroPython 的串流模組還公開了帶有「1」字尾的 C 輔助函式
mp_stream_read1_obj、mp_stream_readinto1_obj與mp_stream_write1_obj,它們會執行單一次底層 I/O 呼叫,而非反覆迴圈直到請求完全滿足為止。這些函式由像machine.UART之類的類別在內部使用,以實作其自身的read/write——但沒有任何標準串流類別將它們繫結為可由 Python 呼叫的read1/readinto1/write1方法。
- class io.StringIO(string: str = '')¶
用於文字模式輸入/輸出的記憶體中類檔案物件(類似以「t」修飾符開啟的一般檔案)。可使用 string 參數指定初始內容(該參數應為一般字串)。實例也支援情境管理器協定(可用於
with陳述式中)。- seek(offset: int, whence: int = 0) int¶
將串流位置變更為相對於 whence 的 offset(
0= 起點,1= 目前位置,2= 結尾),並回傳新的絕對位置。
- close() None¶
關閉串流並釋放底層緩衝區。對已關閉的串流進行進一步操作會擲出
ValueError。
- class io.StringIO(alloc_size: int)
建立一個空的
StringIO物件,預先配置可容納最多 alloc_size 個位元組的空間,如此一來,寫入至多這麼多位元組時就不會重新配置緩衝區(避免記憶體不足的情況或記憶體碎片化)。此建構式是 MicroPython 的擴充功能,僅建議用於特殊情況與系統層級的函式庫,而非最終使用者的應用程式。與 CPython 的差異
此建構式是 MicroPython 的擴充功能。
- seek(offset: int, whence: int = 0) int
將串流位置變更為相對於 whence 的 offset(
0= 起點,1= 目前位置,2= 結尾),並回傳新的絕對位置。
- tell() int
回傳目前的串流位置。
- flush() None
排清寫入緩衝區。對記憶體中串流而言此為無操作。
- close() None
關閉串流並釋放底層緩衝區。對已關閉的串流進行進一步操作會擲出
ValueError。
- getvalue() str
回傳底層緩衝區目前的內容。
- class io.BytesIO(string: bytes = b'')¶
用於二進位模式輸入/輸出的記憶體中類檔案物件(類似以「b」修飾符開啟的一般檔案)。可使用 string 參數指定初始內容(該參數應為 bytes 物件)。實例也支援情境管理器協定(可用於
with陳述式中)。- seek(offset: int, whence: int = 0) int¶
將串流位置變更為相對於 whence 的 offset(
0= 起點,1= 目前位置,2= 結尾),並回傳新的絕對位置。
- close() None¶
關閉串流並釋放底層緩衝區。對已關閉的串流進行進一步操作會擲出
ValueError。
- class io.BytesIO(alloc_size: int)
建立一個空的
BytesIO物件,預先配置可容納最多 alloc_size 個位元組的空間,如此一來,寫入至多這麼多位元組時就不會重新配置緩衝區(避免記憶體不足的情況或記憶體碎片化)。此建構式是 MicroPython 的擴充功能,僅建議用於特殊情況與系統層級的函式庫,而非最終使用者的應用程式。與 CPython 的差異
此建構式是 MicroPython 的擴充功能。
- seek(offset: int, whence: int = 0) int
將串流位置變更為相對於 whence 的 offset(
0= 起點,1= 目前位置,2= 結尾),並回傳新的絕對位置。
- tell() int
回傳目前的串流位置。
- flush() None
排清寫入緩衝區。對記憶體中串流而言此為無操作。
- close() None
關閉串流並釋放底層緩衝區。對已關閉的串流進行進一步操作會擲出
ValueError。
- getvalue() bytes
回傳底層緩衝區目前的內容。