16.2. io — 处理流的核心工具 — Python 文档
16.2. io — 处理流的核心工具
源代码: :source:`Lib/io.py`
16.2.1. 概述
io 模块提供了 Python 处理各种类型 I/O 的主要工具。 I/O 主要有三种类型:文本 I/O、二进制 I/O 和 原始 I/O。 这些是通用类别,每个类别都可以使用各种后备存储。 属于任何这些类别的具体对象称为 文件对象 。 其他常用术语是 stream 和 类文件对象 。
与其类别无关,每个具体的流对象也将具有各种功能:它可以是只读的、只写的或读写的。 它还可以允许任意随机访问(向前或向后寻找任何位置),或仅顺序访问(例如在套接字或管道的情况下)。
所有的流都小心你提供给它们的数据类型。 例如,将 str 对象赋予二进制流的 write()
方法将引发 TypeError
。 因此,将 bytes 对象提供给文本流的 write()
方法。
3.3 版更改: 曾经引发 IOError 的操作现在引发 OSError,因为 IOError 现在是 OSError 的别名。
16.2.1.1. 文本输入/输出
文本 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)需要 字节类对象 并生成 字节 对象。 不执行编码、解码或换行转换。 此类流可用于各种非文本数据,也可用于需要手动控制文本数据处理的情况。
创建二进制流的最简单方法是在模式字符串中使用 open() 和 'b'
:
f = open("myfile.jpg", "rb")
内存中的二进制流也可用作 BytesIO 对象:
f = io.BytesIO(b"some initial binary data: \x00\x01")
二进制流 API 在 BufferedIOBase 的文档中有详细描述。
其他库模块可能提供额外的方式来创建文本或二进制流。 例如,参见 socket.socket.makefile()。
16.2.1.3. 原始输入/输出
原始 I/O(也称为 无缓冲 I/O)通常用作二进制和文本流的低级构建块; 从用户代码直接操作原始流很少有用。 不过,您可以通过在禁用缓冲的二进制模式下打开文件来创建原始流:
f = open("myfile.jpg", "rb", buffering=0)
原始流 API 在 RawIOBase 的文档中有详细描述。
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 可以像以二进制模式打开的文件一样使用。 两者都提供具有随机访问的完整读写功能。
16.2.3. 类层次结构
I/O 流的实现被组织为类的层次结构。 首先是 抽象基类 (ABC),用于指定流的各种类别,然后是提供标准流实现的具体类。
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:
美国广播公司 | 继承 | 存根方法 | Mixin 方法和属性 |
---|---|---|---|
IOBase
|
fileno 、seek 和 truncate
|
close 、closed 、__enter__ 、__exit__ 、flush 、isatty 、__iter__ 、[ X77X]、readable 、readline 、readlines 、seekable 、tell 、writable X166X]
| |
RawIOBase
|
IOBase
|
readinto 和 write
|
继承了 IOBase 方法、read 和 readall
|
BufferedIOBase
|
IOBase
|
detach 、read 、read1 和 write
|
继承了 IOBase 方法、readinto 和 readinto1
|
TextIOBase
|
IOBase
|
detach 、read 、readline 和 write
|
继承了 IOBase 方法、encoding 、errors 和 newlines
|
16.2.3.1. I/O 基类
- class io.IOBase
所有 I/O 类的抽象基类,作用于字节流。 没有公共构造函数。
此类为派生类可以有选择地覆盖的许多方法提供空的抽象实现; 默认实现表示无法读取、写入或搜索的文件。
即使 IOBase 没有声明
read()
、readinto()
或write()
,因为它们的签名会有所不同,但实现和客户端应该将这些方法视为接口的一部分. 此外,当调用它们不支持的操作时,实现可能会引发 ValueError(或 UnsupportedOperation)。用于从文件读取或写入文件的二进制数据的基本类型是 bytes。 其他 bytes-like objects 也被接受为方法参数。 在某些情况下,例如 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
如果流已关闭。
- fileno()
如果存在,则返回流的底层文件描述符(整数)。 如果 IO 对象不使用文件描述符,则会引发 OSError。
- flush()
如果适用,刷新流的写入缓冲区。 这对只读和非阻塞流没有任何作用。
- isatty()
如果流是交互式的(即连接到终端/tty 设备),则返回
True
。
- readable()
如果可以读取流,则返回
True
。 如果False
,read()
将引发 OSError。
- 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 相对于 wherece 指示的位置进行解释。 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 通常提供对底层 OS 设备或 API 的低级访问,并且不会尝试将其封装在高级原语中(这留给缓冲 I/O 和文本 I/O,本文档稍后进行描述)页)。
除了 IOBase 的属性和方法,RawIOBase 还提供了以下方法:
- read(size=- 1)
从对象中读取最多 size 个字节并返回它们。 为方便起见,如果 size 未指定或为 -1,则返回 EOF 之前的所有字节。 否则,只进行一次系统调用。 如果操作系统调用返回少于 size 个字节,则可能返回少于 size 个字节。
如果返回 0 字节,并且 size 不为 0,则表示文件结束。 如果对象处于非阻塞模式并且没有可用字节,则返回
None
。默认实现遵循 readall() 和 readinto()。
- 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)
将字节读入预先分配的、可写的 字节类对象 b,最多使用一次调用底层原始流的 read()(或 ]readinto()) 方法。 返回读取的字节数。
如果底层原始流处于非阻塞模式并且目前没有可用数据,则会引发 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 表示包含字节数据的操作系统级文件。 它实现了 RawIOBase 接口(因此也实现了 IOBase 接口)。
name 可以是以下两种情况之一:
一个字符串或 bytes 对象,表示将打开的文件的路径。 在这种情况下,closefd 必须是
True
(默认值),否则会引发错误。一个整数,表示生成的 FileIO 对象将提供访问权限的现有操作系统级文件描述符的编号。 当 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。
BytesIO 除了来自 BufferedIOBase 和 IOBase 的方法之外,还提供或覆盖这些方法:
- getbuffer()
返回对缓冲区内容的可读和可写视图,而不复制它们。 此外,改变视图将透明地更新缓冲区的内容:
>>> b = io.BytesIO(b"abcdef") >>> view = b.getbuffer() >>> view[2:4] = b"56" >>> b.getvalue() b'ab56ef'
笔记
只要视图存在,就不能调整或关闭 BytesIO 对象。
3.2 版中的新功能。
- getvalue()
返回包含缓冲区全部内容的 bytes。
- read1()
在 BytesIO 中,这与
read()
相同。
- readinto1()
在 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])
从流中返回字节而不推进位置。 最多对原始流进行一次读取以满足调用。 返回的字节数可能比请求的少或多。
- 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。
BufferedWriter 除了来自 BufferedIOBase 和 IOBase 的方法之外,还提供或覆盖这些方法:
- 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 实现了所有 BufferedIOBase' 的方法,除了 detach(),它引发了 UnsupportedOperation。
警告
BufferedRWPair 不会尝试同步对其底层原始流的访问。 您不应该将与 reader 和 writer 相同的对象传递给它; 改用 BufferedRandom。
16.2.3.4. 文本输入/输出
- class io.TextIOBase
文本流的基类。 这个类提供了一个基于字符和行的接口来流 I/O。 没有
readinto()
方法,因为 Python 的字符串是不可变的。 它继承了IOBase。 没有公共构造函数。TextIOBase 除了来自 IOBase 的数据属性和方法之外,还提供或覆盖这些数据属性和方法:
- encoding
用于将流的字节解码为字符串以及将字符串编码为字节的编码名称。
- errors
解码器或编码器的错误设置。
- newlines
一个字符串、一个字符串元组或
None
,表示到目前为止翻译的换行符。 根据实现和初始构造函数标志,这可能不可用。
- buffer
TextIOBase 处理的底层二进制缓冲区(一个 BufferedIOBase 实例)。 这不是 TextIOBase API 的一部分,在某些实现中可能不存在。
- detach()
将底层二进制缓冲区与 TextIOBase 分开并返回。
底层缓冲区被分离后,TextIOBase 处于不可用状态。
某些 TextIOBase 实现,如 StringIO,可能没有底层缓冲区的概念,调用此方法将引发 UnsupportedOperation。
3.1 版中的新功能。
- read(size=- 1)
从流中读取并返回至多 size 个字符作为单个 str。 如果 size 为负数或
None
,读取直到 EOF。
- 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
:“寻找”到当前位置; 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 是一个可选字符串,指定如何处理编码和解码错误。 如果存在编码错误,则通过
'strict'
引发 ValueError 异常(默认None
具有相同效果),或通过'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
,则当 write 调用包含换行符或回车符时,隐含flush()
。如果 write_through 是
True
,则保证不会缓冲对write()
的调用:写入 TextIOWrapper 对象的任何数据都会立即处理到其底层二进制 缓冲区 。3.3 版更改: 添加了 write_through 参数。
3.3 版更改: 默认的 编码 现在是
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 及其父级的方法外,还提供此方法:
- 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
- 一个辅助编解码器,用于解码 通用换行符 模式的换行符。 它继承了 codecs.IncrementalDecoder。
16.2.4. 表现
本节讨论所提供的具体 I/O 实现的性能。
16.2.4.1. 二进制输入/输出
通过即使在用户请求单个字节时也仅读取和写入大块数据,缓冲 I/O 隐藏了调用和执行操作系统的无缓冲 I/O 例程时的任何低效。 增益取决于操作系统和执行的 I/O 类型。 例如,在一些现代操作系统(如 Linux)上,无缓冲磁盘 I/O 可以与缓冲 I/O 一样快。 然而,最重要的是,无论平台和支持设备如何,缓冲 I/O 都能提供可预测的性能。 因此,对于二进制数据,几乎总是最好使用缓冲 I/O 而不是非缓冲 I/O。
16.2.4.2. 文本输入/输出
二进制存储(例如文件)上的文本 I/O 比相同存储上的二进制 I/O 慢得多,因为它需要使用字符编解码器在 unicode 和二进制数据之间进行转换。 这在处理大量文本数据(如大型日志文件)时会变得很明显。 此外,由于使用了重建算法,TextIOWrapper.tell()
和 TextIOWrapper.seek()
都非常慢。
然而,StringIO 是本机内存中的 unicode 容器,其速度与 BytesIO 相似。
16.2.4.3. 多线程
FileIO 对象是线程安全的,因为它们包装的操作系统调用(例如 Unix 下的 read(2)
)也是线程安全的。
二进制缓冲对象(BufferedReader、BufferedWriter、BufferedRandom 和 BufferedRWPair 的实例)使用锁保护其内部结构; 因此一次从多个线程调用它们是安全的。
TextIOWrapper 对象不是线程安全的。
16.2.4.4. 重入性
二进制缓冲对象(BufferedReader、BufferedWriter、BufferedRandom 和 BufferedRWPair 的实例)不可重入。 虽然在正常情况下不会发生可重入调用,但在 信号 处理程序中执行 I/O 时可能会发生重入调用。 如果一个线程试图重新进入它已经访问的缓冲对象,则会引发 RuntimeError。 请注意,这不会禁止其他线程进入缓冲对象。
上述内容隐含地扩展到文本文件,因为 open() 函数会将缓冲对象包装在 TextIOWrapper 中。 这包括标准流,因此也会影响内置函数 print()。