io
--- 用于处理流的核心工具¶
源代码: Lib/io.py
概述¶
io
模块提供了 Python 用于处理各种 I/O 类型的主要工具。I/O 主要有三种类型:文本 I/O、二进制 I/O 和原始 I/O。这些都是通用类别,每种类别都可以使用各种后端存储。属于任一类别的具体对象都称为文件对象。其他常用术语有流和类文件对象。
无论属于哪种类别,每个具体的流对象都具有多种能力:它可以是只读、只写或读写的。它还可以支持任意的随机访问(向前或向后搜寻到任意位置),或只支持顺序访问(例如套接字或管道)。
所有流都严格检查你提供给它们的数据类型。例如,将一个 str
对象传递给二进制流的 write()
方法将会引发 TypeError
。同样,将一个 bytes
对象传递给文本流的 write()
方法也会引发该异常。
文本 I/O¶
文本 I/O 期望并产生 str
对象。这意味着,无论何时,当后端存储原生为字节(例如文件)时,数据的编码和解码都会透明地进行,同时还会选择性地转换平台特定的换行符。
创建文本流的最简单方法是使用 open()
,并可选择指定编码:
f = open("myfile.txt", "r", encoding="utf-8")
内存中的文本流也可以作为 StringIO
对象使用:
f = io.StringIO("some initial text data")
备注
当使用非阻塞流时,请注意,如果流无法立即执行操作,对文本 I/O 对象的读取操作可能会引发 BlockingIOError
。
文本流 API 在 TextIOBase
的文档中有详细描述。
二进制 I/O¶
二进制 I/O(也称为缓冲 I/O)期望接收类字节对象并产生 bytes
对象。不执行任何编码、解码或换行符转换。这类流可用于所有非文本数据,也可用于需要手动控制文本数据处理的情况。
创建二进制流的最简单方法是使用 open()
,并在模式字符串中加入 'b'
:
f = open("myfile.jpg", "rb")
内存中的二进制流也可以作为 BytesIO
对象使用:
f = io.BytesIO(b"some initial binary data: \x00\x01")
二进制流 API 在 BufferedIOBase
的文档中有详细描述。
其他库模块可能提供了创建文本或二进制流的额外方式。例如 socket.socket.makefile()
。
原始 I/O¶
原始 I/O(也称为无缓冲 I/O)通常用作二进制流和文本流的底层构建块;用户代码很少需要直接操作原始流。尽管如此,你还是可以通过在二进制模式下打开文件并禁用缓冲来创建一个原始流:
f = open("myfile.jpg", "rb", buffering=0)
原始流 API 在 RawIOBase
的文档中有详细描述。
文本编码¶
TextIOWrapper
和 open()
的默认编码是与区域设置相关的(locale.getencoding()
)。
然而,许多开发者在打开以 UTF-8 编码的文本文件(例如 JSON、TOML、Markdown 等)时会忘记指定编码,因为大多数 Unix 平台默认使用 UTF-8 区域设置。这会导致 bug,因为对于大多数 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 模式。
可选的 EncodingWarning¶
在 3.10 版新加入: 更多详情请参阅 PEP 597。
要找出哪里使用了默认的区域设置编码,你可以启用 -X warn_default_encoding
命令行选项,或设置 PYTHONWARNDEFAULTENCODING
环境变量。当使用默认编码时,这将发出一个 EncodingWarning
。
如果你提供的 API 使用 open()
或 TextIOWrapper
,并将 encoding=None
作为参数传递,你可以使用 text_encoding()
,这样如果 API 的调用者没有传递 encoding
,就会发出一个 EncodingWarning
。不过,对于新的 API,请考虑默认使用 UTF-8(即 encoding="utf-8"
)。
高层模块接口¶
- io.open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)¶
这是内置函数
open()
的别名。此函数会引发一个审计事件
open
,其参数为 path、mode 和 flags。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 模式返回"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 流的实现被组织成一个类的层次结构。首先是抽象基类 (ABC),它们用于指定流的各种类别,然后是提供标准流实现的具体类。
备注
抽象基类还为某些方法提供了默认实现,以帮助实现具体的流类。例如,BufferedIOBase
提供了 readinto()
和 readline()
的未优化实现。
I/O 层次结构的顶层是抽象基类 IOBase
。它定义了流的基本接口。但是请注意,读写流之间没有分离;如果实现不支持某个给定的操作,允许引发 UnsupportedOperation
。
RawIOBase
ABC 扩展了 IOBase
。它处理流中字节的读写。FileIO
子类化了 RawIOBase
,为机器文件系统中的文件提供接口。
BufferedIOBase
ABC 扩展了 IOBase
。它处理原始二进制流 (RawIOBase
) 上的缓冲。它的子类 BufferedWriter
、BufferedReader
和 BufferedRWPair
分别缓冲可写、可读以及可读可写的原始二进制流。BufferedRandom
为可查找的流提供了缓冲接口。另一个 BufferedIOBase
的子类 BytesIO
是一个内存中的字节流。
TextIOBase
ABC 扩展了 IOBase
。它处理其字节表示文本的流,并处理与字符串之间的编码和解码。TextIOWrapper
继承自 TextIOBase
,是缓冲原始流 (BufferedIOBase
) 的缓冲文本接口。最后,StringIO
是一个用于文本的内存流。
参数名称不属于规范的一部分,只有 open()
的参数才意在用作关键字参数。
下表总结了 io
模块提供的 ABC:
ABC (抽象基类) |
继承自 |
存根方法 (Stub Methods) |
混入方法和属性 (Mixin Methods and Properties) |
---|---|---|---|
|
|
||
|
继承自 |
||
|
继承自 |
||
|
继承自 |
I/O 基类¶
- class io.IOBase¶
所有 I/O 类的抽象基类。
这个类为许多方法提供了空的抽象实现,派生类可以有选择地覆盖这些实现;默认实现代表了一个不可读、不可写或不可查找的文件。
尽管
IOBase
没有声明read()
或write()
,因为它们的签名会变化,但实现和客户端应将这些方法视为接口的一部分。此外,当调用不支持的操作时,实现可能会引发ValueError
(或UnsupportedOperation
)。从文件中读取或写入文件的二进制数据的基本类型是
bytes
。其他类字节对象也可用作方法参数。文本 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
。
- flush()¶
如果适用,刷新流的写缓冲区。对于只读和非阻塞流,此操作无效。
- isatty()¶
如果流是交互式的(即连接到终端/tty 设备),则返回
True
。
- readline(size=-1, /)¶
从流中读取并返回一行。如果指定了 size,则最多读取 size 个字节。
对于二进制文件,行终止符始终为
b'\n'
;对于文本文件,可以使用open()
的 newline 参数来选择可识别的行终止符。
- readlines(hint=-1, /)¶
从流中读取并返回一个行的列表。可以指定 hint 来控制读取的行数:如果到目前为止所有行的总大小(字节/字符数)超过 hint,则不再读取更多行。
hint 值为
0
或更小,以及None
,都被视为无提示。请注意,已经可以使用
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()¶
返回当前流的位置。
- truncate(size=None, /)¶
将流的大小调整为给定的 size 字节(如果未指定 size,则为当前位置)。当前流的位置不变。此调整大小可以扩展或缩小当前文件大小。在扩展的情况下,新文件区域的内容取决于平台(在大多数系统上,额外的字节用零填充)。返回新的文件大小。
在 3.5 版更改: 现在,Windows 在扩展文件时会用零填充。
- writable()¶
如果流支持写入,则返回
True
。如果为False
,write()
和truncate()
将引发OSError
。
- writelines(lines, /)¶
向流中写入一个行的列表。不会添加行分隔符,因此通常提供的每一行末尾都应有行分隔符。
- class io.RawIOBase¶
原始二进制流的基类。它继承自
IOBase
。原始二进制流通常提供对底层操作系统设备或 API 的低级访问,并且不尝试将其封装在高级原语中(此功能在缓冲二进制流和文本流的更高级别完成,本页稍后将描述)。
RawIOBase
除了IOBase
的方法外,还提供了这些方法:- read(size=-1, /)¶
从对象中读取最多 size 个字节并返回。为方便起见,如果 size 未指定或为 -1,则返回直到 EOF 的所有字节。否则,只进行一次系统调用。如果操作系统调用返回的字节数少于 size,则可能返回少于 size 的字节。
如果返回 0 字节,并且 size 不为 0,这表示文件结束。如果对象处于非阻塞模式且没有可用字节,则返回
None
。默认实现委托给
readall()
和readinto()
。
- readall()¶
读取并返回流中直到 EOF 的所有字节,必要时对流进行多次调用。
- class io.BufferedIOBase¶
支持某种缓冲的二进制流的基类。它继承自
IOBase
。与
RawIOBase
的主要区别在于方法read()
、readinto()
和write()
将(分别)尝试读取请求的全部输入或发出所有提供的数据。此外,如果底层原始流处于非阻塞模式,当系统返回会阻塞时,
write()
将引发BlockingIOError
并带有BlockingIOError.characters_written
属性,而read()
将返回已读取的数据,或者如果没有可用数据则返回None
。此外,
read()
方法没有一个委托给readinto()
的默认实现。一个典型的
BufferedIOBase
实现不应该继承自RawIOBase
实现,而是包装一个,就像BufferedWriter
和BufferedReader
所做的那样。BufferedIOBase
除了从IOBase
继承的属性和方法外,还提供或覆盖了以下内容:- raw¶
BufferedIOBase
处理的底层原始流(一个RawIOBase
实例)。这不属于BufferedIOBase
API 的一部分,并且在某些实现中可能不存在。
- detach()¶
将底层原始流从缓冲区中分离出来并返回它。
在原始流被分离后,缓冲区处于不可用状态。
一些缓冲区,如
BytesIO
,没有单一原始流的概念可从此方法返回。它们会引发UnsupportedOperation
。在 3.1 版本加入。
- read(size=-1, /)¶
读取并返回最多 size 个字节。如果参数省略、为
None
或为负数,则尽可能多地读取。返回的字节数可能少于请求的数量。如果流已经到达 EOF,则返回一个空的
bytes
对象。可能会进行多次读取,并且在遇到特定错误时可能会重试调用,更多细节请参阅os.read()
和 PEP 475。返回的字节数少于 size 并不意味着即将到达 EOF。当尽可能多地读取时,如果可用,默认实现将使用
raw.readall
(它应该实现RawIOBase.readall()
),否则将循环读取,直到 read 返回None
、一个空的bytes
或一个不可重试的错误。对于大多数流来说,这是到 EOF,但对于非阻塞流,可能会有更多数据可用。备注
当底层原始流是非阻塞时,实现可能会在没有可用数据时引发
BlockingIOError
或返回None
。io
实现返回None
。
- read1(size=-1, /)¶
读取并返回最多 size 个字节,调用
readinto()
,根据 PEP 475 的规定,如果遇到EINTR
可能会重试。如果 size 是-1
或未提供,实现将为 size 选择一个任意值。备注
当底层原始流是非阻塞时,实现可能会在没有可用数据时引发
BlockingIOError
或返回None
。io
实现返回None
。
- readinto(b, /)¶
将字节读入一个预先分配的可写的类字节对象 b 中,并返回读取的字节数。例如,b 可能是一个
bytearray
。与
read()
类似,可能会对底层原始流发出多次读取,除非后者是交互式的。如果底层原始流处于非阻塞模式,并且当前没有可用数据,则会引发
BlockingIOError
。
- readinto1(b, /)¶
将字节读入预先分配的可写的类字节对象 b 中,最多只调用一次底层原始流的
read()
(或readinto()
)方法。返回读取的字节数。如果底层原始流处于非阻塞模式,并且当前没有可用数据,则会引发
BlockingIOError
。在 3.5 版本加入。
- write(b, /)¶
写入给定的类字节对象 b,并返回写入的字节数(总是等于 b 的字节长度,因为如果写入失败将引发
OSError
)。根据实际实现,这些字节可能会立即写入底层流,或者为了性能和延迟原因而保存在缓冲区中。在非阻塞模式下,如果需要写入的数据无法被原始流在不阻塞的情况下全部接受,则会引发
BlockingIOError
。调用者在此方法返回后可以释放或修改 b,因此实现应仅在方法调用期间访问 b。
原始文件 I/O¶
- class io.FileIO(name, mode='r', closefd=True, opener=None)¶
一个原始二进制流,表示一个包含字节数据的操作系统级文件。它继承自
RawIOBase
。name 可以是以下两种之一:
一个表示将要打开的文件路径的字符串或
bytes
对象。在这种情况下,closefd 必须为True
(默认值),否则将引发错误。一个整数,表示现有操作系统级文件描述符的编号,生成的
FileIO
对象将给予对此的访问权限。当 FileIO 对象关闭时,此文件描述符也将被关闭,除非 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
除了RawIOBase
和IOBase
的属性外,还提供了这些数据属性:- mode¶
构造函数中给定的模式。
- name¶
文件名。如果在构造函数中没有给出名称,则这是文件的文件描述符。
缓冲流¶
缓冲 I/O 流提供了比原始 I/O 更高级别的 I/O 设备接口。
- class io.BytesIO(initial_bytes=b'')¶
一个使用内存中字节缓冲区的二进制流。它继承自
BufferedIOBase
。当调用close()
方法时,缓冲区将被丢弃。可选参数 initial_bytes 是一个包含初始数据的类字节对象。
BytesIO
除了从BufferedIOBase
和IOBase
继承的方法外,还提供或覆盖了这些方法:- getbuffer()¶
返回一个对缓冲区内容的可读写视图,而无需复制它们。此外,修改视图将透明地更新缓冲区的内容:
>>> b = io.BytesIO(b"abcdef") >>> view = b.getbuffer() >>> view[2:4] = b"56" >>> b.getvalue() b'ab56ef'
备注
只要该视图存在,
BytesIO
对象就不能被调整大小或关闭。在 3.2 版本加入。
- readinto1(b, /)¶
在
BytesIO
中,这与readinto()
相同。在 3.5 版本加入。
- class io.BufferedReader(raw, buffer_size=DEFAULT_BUFFER_SIZE)¶
一个缓冲二进制流,为可读、不可查找的
RawIOBase
原始二进制流提供更高级别的访问。它继承自BufferedIOBase
。当从此对象读取数据时,可能会从底层原始流请求更大量的数据,并保存在内部缓冲区中。然后,缓冲的数据可以在后续读取中直接返回。
构造函数为给定的可读 raw 流和 buffer_size 创建一个
BufferedReader
。如果省略 buffer_size,则使用DEFAULT_BUFFER_SIZE
。BufferedReader
除了从BufferedIOBase
和IOBase
继承的方法外,还提供或覆盖了这些方法:- peek(size=0, /)¶
从流中返回字节,但不移动文件指针。返回的字节数可能比请求的要少或多。如果底层的原始流是非阻塞的,并且操作会阻塞,则返回空字节。
- read(size=-1, /)¶
在
BufferedReader
中,这与io.BufferedIOBase.read()
相同。
- read1(size=-1, /)¶
在
BufferedReader
中,这与io.BufferedIOBase.read1()
相同。在 3.7 版更改: size 参数现在是可选的。
- class io.BufferedWriter(raw, buffer_size=DEFAULT_BUFFER_SIZE)¶
一个带缓冲的二进制流,为可写的、不可查找的
RawIOBase
原始二进制流提供了更高级别的访问。它继承自BufferedIOBase
。当向此对象写入时,数据通常会放入一个内部缓冲区。在各种情况下,缓冲区将被写出到底层的
RawIOBase
对象中,包括:当缓冲区对于所有待处理的数据来说太小时;
当调用
flush()
时;当请求
seek()
时(对于BufferedRandom
对象);当
BufferedWriter
对象被关闭或销毁时。
构造函数为给定的可写 raw 流创建一个
BufferedWriter
。如果未指定 buffer_size,则默认为DEFAULT_BUFFER_SIZE
。BufferedWriter
在BufferedIOBase
和IOBase
的方法之外,还提供或重写了以下方法:- flush()¶
强制将缓冲区中保留的字节写入原始流。如果原始流阻塞,则应引发
BlockingIOError
。
- write(b, /)¶
写入 类字节对象 b,并返回写入的字节数。在非阻塞模式下,如果缓冲区需要写出但原始流阻塞,则会引发
BlockingIOError
,并设置其BlockingIOError.characters_written
属性。
- class io.BufferedRandom(raw, buffer_size=DEFAULT_BUFFER_SIZE)¶
一个带缓冲的二进制流,为可查找的
RawIOBase
原始二进制流提供了更高级别的访问。它继承自BufferedReader
和BufferedWriter
。构造函数为第一个参数中给定的可查找原始流创建一个读取器和写入器。如果省略了 buffer_size,则默认为
DEFAULT_BUFFER_SIZE
。BufferedRandom
能够完成BufferedReader
或BufferedWriter
所能做的一切。此外,保证实现了seek()
和tell()
。
- class io.BufferedRWPair(reader, writer, buffer_size=DEFAULT_BUFFER_SIZE, /)¶
一个带缓冲的二进制流,为两个不可查找的
RawIOBase
原始二进制流(一个可读,另一个可写)提供了更高级别的访问。它继承自BufferedIOBase
。reader 和 writer 是分别是可读和可写的
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
或RawIOBase
实例)。这不是TextIOBase
API 的一部分,并且在某些实现中可能不存在。
- detach()¶
将底层二进制缓冲区与
TextIOBase
分离并返回它。底层缓冲区被分离后,
TextIOBase
处于不可用状态。一些
TextIOBase
的实现,如StringIO
,可能没有底层缓冲区的概念,调用此方法将引发UnsupportedOperation
。在 3.1 版本加入。
- seek(offset, whence=SEEK_SET, /)¶
将流位置更改为给定的 offset。行为取决于 whence 参数。whence 的默认值为
SEEK_SET
。SEEK_SET
或0
:从流的开头开始查找(默认值);offset 必须是由TextIOBase.tell()
返回的数字,或者为零。任何其他的 offset 值都会产生未定义的行为。SEEK_CUR
或1
:“查找”到当前位置;offset 必须为零,这是一个无操作(所有其他值都不支持)。SEEK_END
或2
:查找到流的末尾;offset 必须为零(所有其他值都不支持)。
以一个不透明的数字形式返回新的绝对位置。
在 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 给出了流将被解码或编码的编码名称。在 UTF-8 模式下,默认为 UTF-8。否则,默认为
locale.getencoding()
。可以使用encoding="locale"
来显式指定当前区域的编码。更多信息请参见 文本编码。errors 是一个可选字符串,用于指定如何处理编码和解码错误。传递
'strict'
以在出现编码错误时引发ValueError
异常(默认的None
具有相同的效果),或传递'ignore'
来忽略错误。(注意,忽略编码错误可能导致数据丢失。)'replace'
会在格式错误的数据处插入一个替换标记(如'?'
)。'backslashreplace'
会将格式错误的数据替换为反斜杠转义序列。在写入时,可以使用'xmlcharrefreplace'
(替换为适当的 XML 字符引用)或'namereplace'
(替换为\N{...}
转义序列)。任何已通过codecs.register_error()
注册的其他错误处理名称也是有效的。newline 控制如何处理行尾。它可以是
None
、''
、'\n'
、'\r'
和'\r\n'
。它的工作方式如下:从流中读取输入时,如果 newline 是
None
,则启用通用换行模式。输入中的行可以以'\n'
、'\r'
或'\r\n'
结尾,这些都会在返回给调用者之前被翻译成'\n'
。如果 newline 是''
,则启用通用换行模式,但行尾会未经翻译地返回给调用者。如果 newline 是任何其他合法值,输入行仅由给定的字符串终止,并且行尾会未经翻译地返回给调用者。向流中写入输出时,如果 newline 是
None
,则任何写入的'\n'
字符都将被翻译成系统默认的行分隔符os.linesep
。如果 newline 是''
或'\n'
,则不进行翻译。如果 newline 是任何其他合法值,则任何写入的'\n'
字符都将被翻译成给定的字符串。
如果 line_buffering 为
True
,则当对 write 的调用包含换行符或回车符时,会隐式调用flush()
。如果 write_through 为
True
,则对write()
的调用保证不会被缓冲:任何写入TextIOWrapper
对象的数据都会立即传递给其底层的二进制 buffer。在 3.3 版更改: 增加了 write_through 参数。
在 3.3 版更改: 默认的 encoding 现在是
locale.getpreferredencoding(False)
而不是locale.getpreferredencoding()
。不要使用locale.setlocale()
临时更改区域编码,应使用当前区域编码而不是用户首选的编码。在 3.10 版更改: encoding 参数现在支持
"locale"
这个伪编码名称。备注
当底层原始流是非阻塞时,如果读取操作无法立即完成,可能会引发
BlockingIOError
。TextIOWrapper
在TextIOBase
和IOBase
的基础上提供了以下数据属性和方法:- line_buffering¶
行缓冲是否启用。
- write_through¶
写入操作是否立即传递给底层二进制缓冲区。
在 3.7 版本加入。
- reconfigure(*, encoding=None, errors=None, newline=None, line_buffering=None, write_through=None)¶
使用新的 encoding、errors、newline、line_buffering 和 write_through 设置重新配置此文本流。
未指定的参数将保持当前设置,但如果指定了 encoding 而未指定 errors,则使用
errors='strict'
。如果已经从流中读取了数据,则无法更改编码或换行符。另一方面,在写入后更改编码是可能的。
此方法在设置新参数之前会隐式地刷新流。
在 3.7 版本加入。
在 3.11 版更改: 该方法支持
encoding="locale"
选项。
- class io.StringIO(initial_value='', newline='\n')¶
使用内存中文本缓冲区的文本流。它继承自
TextIOBase
。当调用
close()
方法时,文本缓冲区将被丢弃。可以通过提供 initial_value 来设置缓冲区的初始值。如果启用了换行符转换,换行符将像通过
write()
一样进行编码。流的位置被设置在缓冲区的开头,这模拟了以w+
模式打开现有文件,使其准备好从头开始立即写入或覆盖初始值。要模拟以a+
模式打开文件准备追加,请使用f.seek(0, io.SEEK_END)
将流重新定位到缓冲区的末尾。newline 参数的工作方式与
TextIOWrapper
类似,但在向流中写入输出时,如果 newline 为None
,则在所有平台上换行符都写为\n
。StringIO
在TextIOBase
和IOBase
的基础上提供了以下方法:用法示例:
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¶
一个辅助编解码器,用于在通用换行模式下解码换行符。它继承自
codecs.IncrementalDecoder
。
静态类型¶
以下协议可用于为简单的流读取或写入操作的函数和方法参数添加注解。它们都使用了 @typing.runtime_checkable
装饰器。
- class io.Reader[T]¶
用于从文件或其他输入流读取的通用协议。
T
通常是str
或bytes
,但也可以是从流中读取的任何类型。在 3.14 版本加入。
- read()¶
- read(size, /)
从输入流中读取数据并返回。如果指定了 size,它应该是一个整数,并且最多会读取 size 个项目(字节/字符)。
例如:
def read_it(reader: Reader[str]): data = reader.read(11) assert isinstance(data, str)
- class io.Writer[T]¶
用于向文件或其他输出流写入的通用协议。
T
通常是str
或bytes
,但也可以是任何可以写入流中的类型。在 3.14 版本加入。
- write(data, /)¶
将 data 写入输出流,并返回写入的项目数(字节/字符)。
例如:
def write_binary(writer: Writer[bytes]): writer.write(b"Hello world!\n")
有关可用于静态类型检查的其他 I/O 相关协议和类,请参阅 用于处理 I/O 的 ABC 和协议。
性能¶
本节讨论了提供的具体 I/O 实现的性能。
二进制 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()
都相当慢。
多线程¶
FileIO
对象是线程安全的,前提是它们所包装的操作系统调用(例如在 Unix 下的 read(2))也是线程安全的。
二进制缓冲对象(BufferedReader
、BufferedWriter
、BufferedRandom
和 BufferedRWPair
的实例)使用锁来保护其内部结构;因此,可以安全地从多个线程同时调用它们。
TextIOWrapper
对象不是线程安全的。
可重入性¶
二进制缓冲对象(BufferedReader
、BufferedWriter
、BufferedRandom
和 BufferedRWPair
的实例)是不可重入的。虽然在正常情况下不会发生可重入调用,但在 signal
处理程序中进行 I/O 操作时可能会出现。如果一个线程试图重新进入它已经在访问的缓冲对象,会引发 RuntimeError
。注意,这并不禁止另一个线程进入该缓冲对象。
以上内容也隐式地扩展到文本文件,因为 open()
函数会将一个缓冲对象包装在 TextIOWrapper
内部。这包括标准流,因此也影响了内置的 print()
函数。