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")

文字資料串流 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 模式

選擇性加入的編碼警告

Added in version 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() 的別名。

引發一個附帶引數 pathmodeflags稽核事件 open

io.open_code(path)

'rb' 模式開啟提供的檔案。此函式應用於意圖將內容視為可執行的程式碼的情況下。

path 應該要屬於 str 類別,且是個絕對路徑。

這個函式的行為可能會被之前對 PyFile_SetOpenCodeHook() 的呼叫覆寫。然而,假設 path 是個 str 且為絕對路徑,則 open_code(path) 總是與 open(path, 'rb') 有相同行為。覆寫這個行為是為了對檔案進行額外驗證或預處理。

Added in version 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

更多資訊請見 文字編碼

Added in version 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)例外。

从文件读取或写入文件的二进制数据的基本类型为 bytes 。其他 bytes-like objects 也可以作为方法参数。文本I/O类使用 str 数据。

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

IOBase (及其子类)支持迭代器协议,这意味着可以迭代 IOBase 对象以产生流中的行。根据流是二进制流(产生字节)还是文本流(产生字符串),行的定义略有不同。请参见下面的 readline()

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 通常是負數

Added in version 3.1: SEEK_* 常數。

Added in version 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, /)

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

如果回傳了 0 位元組,且 size 不是 0,這表示檔案結尾 (end of file)。如果物件處於非阻塞模式且沒有可用的位元組,則回傳 None

預設的實作會遵守 readall()readinto() 的實作。

readall()

讀取並回傳串流中直到檔案結尾的所有位元組,必要時使用多次對串流的呼叫。

readinto(b, /)

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

write(b, /)

將給定的 bytes-like object (類位元組物件),b,寫入底層的原始串流,並回傳寫入的位元組大小。根據底層原始串流的具體情況,這可能少於 b 的位元組長度,尤其是當它處於非阻塞模式時。如果原始串流設置為非阻塞且無法立即寫入任何單一位元組,則回傳 None。呼叫者在此方法回傳後可以釋放或變更 b,因此實作應該只在方法呼叫期間存取 b

class io.BufferedIOBase

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

RawIOBase 的主要差異在於,read()readinto()write() 方法將分別嘗試讀取所請求的盡可能多的輸入,或消耗所有給定的輸出,即使可能需要進行多於一次的系統呼叫。

此外,如果底層的原始串流處於非阻塞模式且無法提供或接收足夠的資料,這些方法可能會引發 BlockingIOError 例外;與 RawIOBase 不同之處在於,它們永遠不會回傳 None

此外,read() 方法不存在一個遵從 readinto() 的預設實作。

一個典型的 BufferedIOBase 實作不應該繼承自一個 RawIOBase 的實作,而是應該改用包裝的方式,像 BufferedWriterBufferedReader 那樣的作法。

BufferedIOBase 除了提供或覆寫來自 IOBase 的資料屬性和方法以外,還包含了這些:

raw

底層的原始串流(一個 RawIOBase 實例),BufferedIOBase 處理的對象。這不是 BufferedIOBase API 的一部分,且在某些實作可能不存在。

detach()

將底層的原始串流從緩衝區中分離出來,並回傳它。

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

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

Added in version 3.1.

read(size=-1, /)

讀取並回傳最多 size 個位元組。如果引數被省略、為 None 或為負值,將讀取並回傳資料直到達到 EOF 為止。如果串流已經處於 EOF,則回傳一個空的 bytes 物件。

如果引數為正數,且底層原始串流不是互動式的,可能會發出多次原始讀取來滿足位元組數量(除非首先達到 EOF)。但對於互動式原始串流,最多只會發出一次原始讀取,且短少的資料不表示 EOF 即將到來。

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

read1(size=-1, /)

讀取並回傳最多 size 個位元組,最多呼叫一次底層原始串流的 read() (或 readinto()) 方法。如果你正在 BufferedIOBase 物件之上實作自己的緩衝區,這可能會很有用。

如果 size-1 (預設值),則會回傳任意數量的位元組(除非達到 EOF,否則會超過零)。

readinto(b, /)

讀取位元組到一個預先分配的、可寫的 bytes-like object b 當中,並回傳讀取的位元組數量。例如,b 可能是一個 bytearray

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

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

readinto1(b, /)

讀取位元組到一個預先分配的、可寫的 bytes-like object b 中,最多呼叫一次底層原始串流的 read() (或 readinto())方法。此方法回傳讀取的位元組數量。

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

Added in version 3.5.

write(b, /)

寫入給定的 bytes-like objectb,並回傳寫入的位元組數量(總是等於 b 的長度,以位元組計,因為如果寫入失敗將會引發 OSError)。根據實際的實作,這些位元組可能會立即寫入底層串流,或出於性能和延遲的緣故而被留在緩衝區當中。

當處於非阻塞模式時,如果需要將資料寫入原始串流,但它無法接受所有資料而不阻塞,則會引發 BlockingIOError

呼叫者可以在此方法回傳後釋放或變更 b,因此實作應該僅在方法呼叫期間存取 b

原始檔案 I/O

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

一個代表包含位元組資料的 OS 層級檔案的原始二進制串流。它繼承自 RawIOBase

name 可以是兩種事物之一:

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

  • 代表一个现有 OS 层级文件描述符的号码的整数,作为结果的 FileIO 对象将可访问该文件。 当 FileIO 对象被关闭时此 fd 也将被关闭,除非 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 是一个包含初始数据的 bytes-like object

BytesIO 在继承自 BufferedIOBaseIOBase 的成员以外还提供或重写了下列方法:

getbuffer()

返回一个对应于缓冲区内容的可读写视图而不必拷贝其数据。 此外,改变视图将透明地更新缓冲区内容:

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

備註

只要视图保持存在,BytesIO 对象就无法被改变大小或关闭。

Added in version 3.2.

getvalue()

返回包含整个缓冲区内容的 bytes

read1(size=-1, /)

BytesIO 中,这与 read() 相同。

在 3.7 版的變更: size 参数现在是可选的。

readinto1(b, /)

BytesIO 中,这与 readinto() 相同。

Added in version 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, /)

读取并返回 size 个字节,如果 size 未给定或为负值,则读取至 EOF 或是在非阻塞模式下读取调用将会阻塞。

read1(size=-1, /)

在原始流上通过单次调用读取并返回至多 size 个字节。 如果至少缓冲了一个字节,则只返回缓冲的字节。 在其他情况下,将执行一次原始流读取。

在 3.7 版的變更: size 参数现在是可选的。

class io.BufferedWriter(raw, buffer_size=DEFAULT_BUFFER_SIZE)

一个提供对可写、不可定位的 RawIOBase 原始二进制流的高层级访问的缓冲二进制流。 它继承自 BufferedIOBase

当写入到此对象时,数据通常会被放入到内部缓冲区中。 缓冲区将在满足某些条件的情况下被写到下层的 RawIOBase 对象,包括:

该构造器会为给定的可写 raw 流创建一个 BufferedWriter。 如果未给定 buffer_size,则使用默认的 DEFAULT_BUFFER_SIZE

BufferedWriter 在继承自 BufferedIOBaseIOBase 的成员以外还提供或重写了下列方法:

flush()

将缓冲区中保存的字节数据强制放入原始流。 如果原始流发生阻塞则应当引发 BlockingIOError

write(b, /)

写入 bytes-like object b 并返回写入的字节数。 当处于非阻塞模式时,如果缓冲区需要被写入但原始流发生阻塞则将引发 BlockingIOError

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

TextIOBase 在来自 IOBase 的成员以外还提供或重写了以下数据属性和方法:

encoding

用于将流的字节串解码为字符串以及将字符串编码为字节串的编码格式名称。

errors

解码器或编码器的错误设置。

newlines

一个字符串、字符串元组或者 None,表示目前已经转写的新行。 根据具体实现和初始构造器旗标的不同,此属性或许会不可用。

buffer

TextIOBase 处理的下层二进制缓冲区(为一个 BufferedIOBase 的实例)。 它不是 TextIOBase API 的组成部分并且不存在于某些实现中。

detach()

TextIOBase 分离出下层二进制缓冲区并将其返回。

在下层缓冲区被分离后,TextIOBase 将处于不可用的状态。

某些 TextIOBase 的实现,例如 StringIO 可能并无下层缓冲区的概念,因此调用此方法将引发 UnsupportedOperation

Added in version 3.1.

read(size=-1, /)

从流中读取至多 size 个字符并以单个 str 的形式返回。 如果 size 为负值或 None,则读取至 EOF。

readline(size=-1, /)

读取至换行符或 EOF 并返回单个 str。 如果流已经到达 EOF,则将返回一个空字符串。, an empty string is returned.

如果指定了 size ,最多将读取 size 个字符。

seek(offset, whence=SEEK_SET, /)

将流位置改为给定的 offset。 具体行为取决于 whence 形参。 whence 的默认值为 SEEK_SET

  • SEEK_SET0: 从流的起始位置开始查找(默认值);offset 必须为 TextIOBase.tell() 所返回的数值或为零。 任何其他 offset 值都将导致未定义的行为。

  • SEEK_CUR1: "查找" 到当前位置;offset 必须为零,表示无操作(所有其他值均不受支持)。

  • SEEK_END2: 查找到流的末尾;offset 必须为零(所有其他值均不受支持)。

以不透明数字形式返回新的绝对位置。

Added in version 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 给出流的解码或编码要使用的编码格式的名称。 它默认为 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,则将启用 universal newlines 模式。 输入中的行结束符可以为 '\n', '\r''\r\n',在返回给调用者之前它们会被统一转写为 '\n'。 如果 newline'',也会启用通用换行模式,但行结束符会不加转写即返回给调用者。 如果 newline 具有任何其他合法的值,则输入行将仅由给定的字符串结束,并且行结束符会不加转写即返回给调用者。

  • 将输出写入流时,如果 newlineNone,则写入的任何 '\n' 字符都将转换为系统默认行分隔符 os.linesep。如果 newline'''\n',则不进行翻译。如果 newline 是任何其他合法值,则写入的任何 '\n' 字符将被转换为给定的字符串。

如果 line_bufferingTrue,则当一个写入调用包含换行或回车符时将会应用 flush()

如果 write_throughTrue,则对 write() 的调用会确保不被缓冲:在 TextIOWrapper 对象上写入的任何数据会立即交给其下层的 buffer 来处理。

在 3.3 版的變更: 已添加 write_through 参数

在 3.3 版的變更: 默认的 encoding 现在将为 locale.getpreferredencoding(False) 而非 locale.getpreferredencoding()。 不要使用 locale.setlocale() 来临时改变区域编码格式,要使用当前区域编码格式而不是用户的首选编码格式。

在 3.10 版的變更: encoding 参数现在支持 "locale" 作为编码格式名称。

TextIOWrapper 在继承自 TextIOBaseIOBase 的现有成员以外还提供了以下数据属性和方法:

line_buffering

是否启用行缓冲。

write_through

写入是否要立即传给下层的二进制缓冲。

Added in version 3.7.

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

使用 encoding, errors, newline, line_bufferingwrite_through 的新设置来重新配置此文本流。

未指定的形参将保留当前设定,例外情况是当指定了 encoding 但未指定 errors 时将会使用 errors='strict'

如果已经有数据从流中被读取则将无法再改变编码格式或行结束符。 另一方面,在写入数据之后再改变编码格式则是可以的。

此方法会在设置新的形参之前执行隐式的流刷新。

Added in version 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): 保持当前流位置不变。

任何其他参数组合均无效,并可能引发异常。

也參考

os.SEEK_SET, os.SEEK_CURos.SEEK_END

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

StringIO 在继承自 TextIOBaseIOBase 的现有成员以外还提供了以下方法:

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

用于在 universal newlines 模式下解码换行符的辅助编解码器。 它继承自 codecs.IncrementalDecoder

性能

本节讨论所提供的具体 I/O 实现的性能。

二進位 (Binary) 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)) 是线程安全的情况下也是线程安全的。

二进制缓冲对象(例如 BufferedReader, BufferedWriter, BufferedRandomBufferedRWPair)使用锁来保护其内部结构;因此,可以安全地一次从多个线程中调用它们。

TextIOWrapper 对象不再是线程安全的。

可重入性

二进制缓冲对象( BufferedReaderBufferedWriterBufferedRandomBufferedRWPair 的实例)不是可重入的。虽然在正常情况下不会发生可重入调用,但仍可能会在 signal 处理程序执行 I/O 时产生。如果线程尝试重入已经访问的缓冲对象,则会引发 RuntimeError 。注意,这并不禁止其他线程进入缓冲对象。

上面的内容隐式地扩展到文本文件中,因为 open() 函数将把缓冲对象封装在 TextIOWrapper 中。 这包括标准流,因而也会影响内置的 print() 函数。