16.2. io
—用于处理流的核心工具¶
源代码: Lib/io.py
16.2.1. 概述¶
io
模块提供Python的主要设施来处理各种类型的I/O。有三种主要类型的I/O:文本I/O,二进制I/O 和 原始I/O。这些是通用类别,并且可以为它们中的每一个使用各种后备存储。属于这些类别中的任何一个的具体对象被称为 file object。其他常用术语是 stream 和 文件状对象。
独立于其类别,每个具体的流对象也将具有各种能力:它可以是只读的,只写的或读写的。它还可以允许任意随机访问(向前或向后寻找任何位置),或只允许顺序访问(例如在套接字或管道的情况下)。
所有流都仔细考虑您给他们的数据类型。例如,给 str
对象提供二进制流的 write()
方法将产生 TypeError
。所以将给一个 bytes
对象的文本流的 write()
方法。
16.2.1.1. 文本I/O¶
文本I/O期望并生成 str
对象。这意味着每当后备存储器由字节(例如在文件的情况下)本地地做成时,数据的编码和解码被透明地以及平台特定的换行字符的可选的翻译。
创建文本流最简单的方法是使用 open()
,可选择指定编码:
f = open("myfile.txt", "r", encoding="utf-8")
内存中的文本流也可用作 StringIO
对象:
f = io.StringIO("some initial text data")
文本流API在 TextIOBase
的文档中详细描述。
16.2.1.2. 二进制I/O¶
二进制I/O(也称为 缓冲I/O)期望 字节状对象 并产生 bytes
对象。不执行编码,解码或换行。这种类别的流可以用于所有种类的非文本数据,并且当需要对文本数据的处理进行手动控制时。
创建二进制流的最简单的方法是在模式字符串中使用 'b'
的 open()
:
f = open("myfile.jpg", "rb")
内存中的二进制流也可用作 BytesIO
对象:
f = io.BytesIO(b"some initial binary data: \x00\x01")
二进制流API在 BufferedIOBase
的文档中详细描述。
其他库模块可以提供创建文本或二进制流的附加方式。例如参见 socket.socket.makefile()
。
16.2.2. 高级模块接口¶
-
io.
open
(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)¶ 这是内置
open()
函数的别名。
-
exception
io.
BlockingIOError
¶ 这是内置
BlockingIOError
异常的兼容性别名。
-
exception
io.
UnsupportedOperation
¶ 当在流上调用不受支持的操作时引发的
OSError
和ValueError
的继承异常。
16.2.2.1. 内存流¶
也可以使用 str
或 bytes-like object 作为用于读取和写入的文件。对于字符串 StringIO
可以像在文本模式下打开的文件一样使用。 BytesIO
可以像在二进制模式下打开的文件一样使用。两者都提供随机存取的完全读写能力。
参见
sys
包含标准IO流:
sys.stdin
,sys.stdout
和sys.stderr
。
16.2.3. 类层次结构¶
I/O流的实现被组织为类的层次结构。第一 抽象基类 (ABC),用于指定流的各种类别,然后具体类提供标准流实现。
注解
抽象基类还提供了一些方法的默认实现,以帮助实现具体的流类。例如,
BufferedIOBase
提供readinto()
和readline()
的未优化实现。
在I/O层次结构的顶部是抽象基类 IOBase
。它定义了流的基本接口。然而,请注意,在读取和写入流之间没有分离;如果它们不支持给定的操作,则允许实现提高 UnsupportedOperation
。
RawIOBase
ABC延伸 IOBase
。它处理字节读取和写入流。 FileIO
子类 RawIOBase
为机器文件系统中的文件提供接口。
BufferedIOBase
ABC处理原始字节流(RawIOBase
)上的缓冲。其子类,BufferedWriter
,BufferedReader
和 BufferedRWPair
缓冲区流,可读,可写,并且可读和可写。 BufferedRandom
向随机存取流提供缓冲接口。另一个 BufferedIOBase
子类,BytesIO
,是一个内存中字节流。
TextIOBase
ABC是 IOBase
的另一个子类,它处理其字节表示文本的流,并处理来自字符串的编码和解码。 TextIOWrapper
,它扩展它,是缓冲的原始流(BufferedIOBase
)的缓冲文本接口。最后,StringIO
是一个用于文本的内存流。
参数名称不是规范的一部分,只有 open()
的参数用作关键字参数。
下表总结了 io
模块提供的ABC:
ABC |
继承 |
存根方法 |
Mixin方法和属性 |
---|---|---|---|
|
|
||
|
继承 |
||
|
继承 |
||
|
继承 |
16.2.3.1. I/O基类¶
-
class
io.
IOBase
¶ 所有I/O类的抽象基类,作用于字节流。没有公共构造函数。
这个类为许多方法提供了空的抽象实现,派生类可以有选择地重写;默认实现代表无法读取,写入或查找的文件。
即使
IOBase
不声明read()
,readinto()
或write()
,因为它们的签名会有所不同,实现和客户端应该考虑这些方法的一部分接口。此外,当调用不支持的操作时,实现可以产生ValueError
(或UnsupportedOperation
)。用于从文件读取或写入文件的二进制数据的基本类型是
bytes
。其他 字节状对象 也被接受为方法参数。在某些情况下,例如readinto()
,需要诸如bytearray
的可写对象。文本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,则不会再读取行。
注意,已经可以使用
for line in file: ...
对文件对象进行迭代而不调用file.readlines()
。
-
seek
(offset[, whence])¶ 将流位置更改为给定字节 offset。 offset 相对于由 whence 指示的位置被解释。 whence 的默认值为
SEEK_SET
。 whence 的值为:SEEK_SET
或0
- 流的开始(默认); offset 应为零或正SEEK_CUR
或1
- 当前流位置; offset 可能为负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
¶ 原始二进制I/O的基类。它继承
IOBase
。没有公共构造函数。原始二进制I/O通常提供对底层操作系统设备或API的低级访问,并且不尝试将其封装在高级原语中(这将留给缓冲I/O和文本I/O,稍后在本文中描述页)。
除了来自
IOBase
的属性和方法,RawIOBase
提供以下方法:-
read
(size=-1)¶ 从对象中读取 size 字节并返回它们。为了方便起见,如果 size 未指定或-1,则调用
readall()
。否则,只有一个系统调用。如果操作系统调用返回少于 size 个字节,则可能返回少于 size 个字节。如果返回0字节,并且 size 不为0,则表示文件结束。如果对象处于非阻塞模式并且没有字节可用,则返回
None
。
-
readall
()¶ 读取并返回流中的所有字节,直到EOF,如果必要,使用多个调用流。
-
readinto
(b)¶ 将字节读入预分配的,可写的 bytes-like object b,并返回读取的字节数。如果对象处于非阻塞模式并且没有字节可用,则返回
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
实现,而是包装一个,像BufferedWriter
和BufferedReader
。BufferedIOBase
提供或覆盖除来自IOBase
的那些方法和属性之外的这些方法和属性:-
raw
¶ BufferedIOBase
处理的底层原始流(RawIOBase
实例)。这不是BufferedIOBase
API的一部分,在某些实现上可能不存在。
-
detach
()¶ 从缓冲区分离下层原始流并返回它。
在原始流已经分离之后,缓冲器处于不可用状态。
一些缓冲区(如
BytesIO
)没有从此方法返回的单个原始流的概念。他们提高UnsupportedOperation
。3.1 新版功能.
-
read
(size=-1)¶ 读取并返回 size 字节。如果省略参数,
None
或负数,则读取并返回数据,直到到达EOF。如果流已经处于EOF,则返回空bytes
对象。如果参数是正的,并且基础原始流不是交互式的,则可以发出多个原始读取以满足字节计数(除非首先到达EOF)。但对于交互式原始流,最多只会发出一次原始读取,并且较短的结果并不意味着EOF即将来临。
如果底层原始流处于非阻塞模式,并且此时没有可用数据,则引发
BlockingIOError
。
-
read1
(size=-1)¶ 读取并返回到 size 字节,最多一次调用底层原始流的
read()
(或readinto()
)方法。如果您在BufferedIOBase
对象的顶部实现自己的缓冲,这可能很有用。
-
readinto
(b)¶ 将字节读入预分配的,可写的 bytes-like object b 并返回读取的字节数。
像
read()
一样,可以向底层原始流发出多个读取,除非后者是交互式的。如果底层原始流处于非阻塞模式,并且此时没有可用数据,则引发
BlockingIOError
。
-
readinto1
(b)¶ 使用至多一次对底层原始流的
read()
(或readinto()
)方法的调用,将字节读入预分配的,可写入的 bytes-like object b。返回读取的字节数。如果底层原始流处于非阻塞模式,并且此时没有可用数据,则引发
BlockingIOError
。3.5 新版功能.
-
write
(b)¶ 写给定的 bytes-like object,b,并返回写入的字节数(总是等于 b 的长度,以字节为单位,因为如果写入失败,
OSError
将被引发)。根据实际实现,这些字节可以容易地写入底层流,或者由于性能和等待时间的原因保持在缓冲器中。当处于非阻塞模式时,如果数据需要写入原始流,但是它不能接受所有数据而不阻塞,则会引发
BlockingIOError
。在此方法返回后,调用者可以释放或改变 b,因此实现应该只在方法调用期间访问 b。
-
16.2.3.2. 原始文件I/O¶
-
class
io.
FileIO
(name, mode='r', closefd=True, opener=None)¶ FileIO
表示包含字节数据的OS级别文件。它实现了RawIOBase
接口(因此也实现了IOBase
接口)。name 可以是以下两种情况之一:
表示将要打开的文件的路径的字符串或
bytes
对象。在这种情况下,closefd必须是True
(默认值),否则会引发错误。一个整数,表示结果
FileIO
对象将给予访问权限的现有OS级文件描述符的编号。当FileIO对象关闭时,fd也将关闭,除非 closefd 设置为False
。
mode 可以是用于阅读(默认),书写,独占创建或附加的
'r'
,'w'
,'x'
或'a'
。如果文件在打开以进行写入或追加时不存在,则将创建该文件;它将被打开以便写入时被截断。如果FileExistsError
在打开时已存在,则将被引发。打开用于创建的文件意味着写入,因此此模式的行为方式与'w'
类似。将'+'
添加到模式以允许同时读取和写入。read()
(当使用正参数调用时),此类上的readinto()
和write()
方法将只进行一次系统调用。可以通过将可调用项传递为 opener 来使用自定义打开程序。然后通过使用(name,flags)调用 opener 来获取文件对象的基础文件描述符。 opener 必须返回一个打开的文件描述符(传递
os.open
作为 opener 导致类似于传递None
的功能)。新创建的文件是 不可继承。
有关使用 opener 参数的示例,请参阅
open()
内置函数。在 3.3 版更改: 添加了 opener 参数。添加
'x'
模式。在 3.4 版更改: 该文件现在是不可继承的。
除了来自
IOBase
和RawIOBase
的属性和方法之外,FileIO
还提供以下数据属性:-
mode
¶ 在构造函数中给出的模式。
-
name
¶ 文件名。这是在构造函数中没有给出名称时文件的文件描述符。
16.2.3.3. 缓冲流¶
缓冲I/O流为I/O设备提供了比原始I/O更高级别的接口。
-
class
io.
BytesIO
([initial_bytes])¶ 使用内存中字节缓冲区的流实现。它继承
BufferedIOBase
。当调用close()
方法时,将丢弃缓冲区。可选参数 initial_bytes 是包含初始数据的 bytes-like object。
除了来自
BufferedIOBase
和IOBase
的BytesIO
之外,BytesIO
还提供或覆盖这些方法:
-
class
io.
BufferedReader
(raw, buffer_size=DEFAULT_BUFFER_SIZE)¶ 一个缓冲区,提供对可读,顺序
RawIOBase
对象的更高级访问。它继承BufferedIOBase
。当从该对象读取数据时,可以从底层原始流请求更大量的数据,并保存在内部缓冲器中。然后可以在后续读取时直接返回缓冲的数据。构造函数为给定的可读 raw 流和 buffer_size 创建
BufferedReader
。如果省略 buffer_size,则使用DEFAULT_BUFFER_SIZE
。除了来自
BufferedIOBase
和IOBase
的BufferedReader
之外,BufferedReader
还提供或覆盖这些方法:-
peek
([size])¶ 从流中返回字节,但不推进位置。对原始流最多只能进行一次读取以满足调用。返回的字节数可以小于或大于请求的字节数。
-
read
([size])¶ 读取和返回 size 字节,或者如果 size 未给定或为负,直到EOF或读取调用将在非阻塞模式下阻塞。
-
read1
(size)¶ 读取并返回到 size 字节,原始流只有一个调用。如果至少一个字节被缓冲,则仅返回被缓冲的字节。否则,进行一个原始流读取调用。
-
-
class
io.
BufferedWriter
(raw, buffer_size=DEFAULT_BUFFER_SIZE)¶ 一个缓冲区,提供对可写,顺序
RawIOBase
对象的更高级访问。它继承BufferedIOBase
。写入此对象时,通常将数据放入内部缓冲区。缓冲区将在各种条件下写入底层RawIOBase
对象,包括:当缓冲器对于所有未决数据来说太小时;
当
flush()
被调用时;当
seek()
被请求时(对于BufferedRandom
对象);当
BufferedWriter
对象被关闭或销毁时。
构造函数为给定的可写 raw 流创建
BufferedWriter
。如果没有给出 buffer_size,它默认为DEFAULT_BUFFER_SIZE
。除了来自
BufferedIOBase
和IOBase
的BufferedWriter
之外,BufferedWriter
还提供或覆盖这些方法:-
flush
()¶ 将缓冲区中保存的字节强制为原始流。如果原始流被阻塞,应该引发
BlockingIOError
。
-
write
(b)¶ 写入 bytes-like object,b,并返回写入的字节数。当处于非阻塞模式时,如果缓冲区需要被写出而原始流被阻塞,则引发
BlockingIOError
。
-
class
io.
BufferedRandom
(raw, buffer_size=DEFAULT_BUFFER_SIZE)¶ 缓冲接口,用于随机访问流。它继承
BufferedReader
和BufferedWriter
,并进一步支持seek()
和tell()
功能。构造函数为第一个参数中给出的可寻找的原始流创建一个读写器。如果省略 buffer_size,它默认为
DEFAULT_BUFFER_SIZE
。BufferedRandom
能够任何BufferedReader
或BufferedWriter
能做的。
-
class
io.
BufferedRWPair
(reader, writer, buffer_size=DEFAULT_BUFFER_SIZE)¶ 缓冲I/O对象将两个单向
RawIOBase
对象(一个可读,另一个可写)组合为单个双向端点。它继承BufferedIOBase
。reader 和 writer 是分别可读和可写的
RawIOBase
对象。如果省略 buffer_size,它默认为DEFAULT_BUFFER_SIZE
。BufferedRWPair
实现除detach()
之外的所有BufferedIOBase
方法,其提高UnsupportedOperation
。警告
BufferedRWPair
不尝试同步对其底层原始流的访问。你不应该把它作为读者和作家的同一个对象;请使用BufferedRandom
。
16.2.3.4. 文本I/O¶
-
class
io.
TextIOBase
¶ 文本流的基类。此类为流I/O提供了一个基于字符和基于行的接口。没有
readinto()
方法,因为Python的字符串是不可变的。它继承IOBase
。没有公共构造函数。除了来自
IOBase
的属性和方法之外,TextIOBase
还提供或覆盖这些数据属性和方法:-
encoding
¶ 用于将流的字节解码为字符串,以及将字符串编码为字节的编码的名称。
-
errors
¶ 解码器或编码器的错误设置。
-
newlines
¶ 字符串,字符串的元组或
None
,指示到目前为止翻译的换行符。根据实现和初始构造函数标志,这可能不可用。
-
buffer
¶ TextIOBase
处理的底层二进制缓冲区(BufferedIOBase
实例)。这不是TextIOBase
API的一部分,在某些实现中可能不存在。
-
detach
()¶ 从
TextIOBase
分离底层二进制缓冲区并返回它。在底层缓冲区已经分离之后,
TextIOBase
处于不可用状态。一些
TextIOBase
实现,如StringIO
,可能没有底层缓冲区的概念,并调用此方法将提高UnsupportedOperation
。3.1 新版功能.
-
readline
(size=-1)¶ 阅读直到换行或EOF并返回单个
str
。如果流已经处于EOF,则返回一个空字符串。如果指定了 size,将读取最多 size 个字符。
-
seek
(offset[, whence])¶ 将流位置更改为给定的 offset。行为取决于 whence 参数。 whence 的默认值为
SEEK_SET
。SEEK_SET
或0
:从流的开始寻找(默认值); offset 必须是由TextIOBase.tell()
返回的数字,或为零。任何其他 offset 值产生未定义的行为。SEEK_CUR
或1
:“seek”到当前位置; 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 给出了流将被解码或编码的编码的名称。它默认为
locale.getpreferredencoding(False)
。errors 是一个可选字符串,指定如何处理编码和解码错误。如果存在编码错误(默认的
None
具有相同的效果),则传递'strict'
以引发ValueError
异常,或者通过'ignore'
忽略错误。 (请注意,忽略编码错误可能导致数据丢失。)'replace'
会导致替换标记(例如'?'
)插入存在格式错误的数据的位置。'backslashreplace'
导致格式错误的数据被反斜杠转义序列替换。写入时,可以使用'xmlcharrefreplace'
(替换为适当的XML字符引用)或'namereplace'
(替换为\N{...}
转义序列)。已使用codecs.register_error()
注册的任何其他错误处理名称也有效。newline 控制如何处理行尾。它可以是
None
,''
,'\n'
,'\r'
和'\r\n'
。它的工作原理如下:当从流读取输入时,如果 newline 是
None
,则启用 universal newlines 模式。输入中的行可以以'\n'
,'\r'
或'\r\n'
结尾,并且在返回给调用者之前,这些行被转换为'\n'
。如果是''
,则启用通用换行符模式,但行结束将返回给未转换的调用者。如果它具有任何其他合法值,则输入行仅由给定字符串终止,并且行结尾被返回给未经翻译的调用者。当将输出写入流时,如果 newline 是
None
,则写入的任何'\n'
字符都将转换为系统默认行分隔符os.linesep
。如果 newline 是''
或'\n'
,则不进行翻译。如果 newline 是任何其他合法值,写入的任何'\n'
字符都将转换为给定字符串。
如果 line_buffering 是
True
,则当写入调用包含换行符时,暗示flush()
。如果 write_through 是
True
,则保证对write()
的调用不被缓冲:写在TextIOWrapper
对象上的任何数据被立即处理到其基本的二进制 buffer。在 3.3 版更改: 已添加 write_through 参数。
在 3.3 版更改: 默认的 encoding 现在是
locale.getpreferredencoding(False)
,而不是locale.getpreferredencoding()
。不要使用locale.setlocale()
临时更改区域设置编码,请使用当前区域设置编码,而不是用户首选编码。TextIOWrapper
除了TextIOBase
及其父代之外还提供一个属性:-
line_buffering
¶ 是否启用线路缓冲。
-
class
io.
StringIO
(initial_value='', newline='\n')¶ 用于文本I/O的内存中流。当调用
close()
方法时,将丢弃文本缓冲区。可以通过提供 initial_value 来设置缓冲器的初始值。如果启用了换行,则换行符将按
write()
进行编码。流被定位在缓冲器的开始处。newline 参数的工作方式类似于
TextIOWrapper
。默认值是仅将\n
字符视为行的末尾,并且不进行换行。如果 newline 设置为None
,则在所有平台上将换行符写为\n
,但是在读取时仍然执行通用换行解码。StringIO
除了来自TextIOBase
及其父母的方法之外还提供这种方法:用法示例:
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
。
16.2.4. 性能¶
本节讨论所提供的具体I/O实现的性能。
16.2.4.1. 二进制I/O¶
通过只读取和写入大量数据,即使用户请求单个字节,缓冲I/O隐藏了调用和执行操作系统的未缓冲I/O例程的任何低效率。增益取决于OS和执行的I/O的种类。例如,在某些现代操作系统(如Linux)上,无缓冲磁盘I/O可以与缓冲I/O一样快。然而,底线是缓冲I/O提供可预测的性能,而不管平台和后备设备。因此,对于二进制数据,几乎总是优选使用缓冲的I/O而不是无缓冲的I/O。
16.2.4.2. 文本I/O¶
二进制存储(例如文件)上的文本I/O明显比同一存储上的二进制I/O慢,因为它需要使用字符编解码器在Unicode和二进制数据之间进行转换。这可以变得明显处理大量的文本数据,如大日志文件。此外,由于使用重建算法,TextIOWrapper.tell()
和 TextIOWrapper.seek()
都相当缓慢。
16.2.4.3. 多线程¶
FileIO
对象是线程安全的,操作系统调用(例如Unix下的 read(2)
),它们也是线程安全的。
二进制缓冲对象(BufferedReader
,BufferedWriter
,BufferedRandom
和 BufferedRWPair
的实例)使用锁来保护它们的内部结构;因此可以安全地同时从多个线程调用它们。
TextIOWrapper
对象不是线程安全的。
16.2.4.4. 再入¶
二进制缓冲对象(BufferedReader
,BufferedWriter
,BufferedRandom
和 BufferedRWPair
的实例)不可重入。虽然可重入调用在正常情况下不会发生,但它们可能来自于在 signal
处理程序中执行I/O。如果线程试图重新输入它已经访问的缓冲对象,则引发 RuntimeError
。注意,这并不禁止不同的线程进入缓冲对象。
上面隐含地扩展到文本文件,因为 open()
函数将在 TextIOWrapper
内包装缓冲的对象。这包括标准流,因此也影响内置函数 print()
。