15.2. io-使用流的核心工具

2.6 版的新Function。

io模块提供 Python 接口以进行流处理。在 Python 2.x 下,建议使用它作为内置file对象的替代方法,但是在 Python 3.x 中,它是访问文件和流的默认接口。

Note

由于此模块主要是为 Python 3.x 设计的,因此必须注意,本文档中对“字节”的所有使用均指代str类型(其中bytes是别名),而对“文本”的所有用法均指代到unicode类型。此外,这两种类型在io API 中不可互换。

I/O 层次结构的顶部是抽象 Base ClassIOBase。它定义了流的基本接口。但是请注意,对流的读取和写入之间没有分隔。如果实现不支持给定的操作,则允许它们引发IOError

扩展IOBaseRawIOBase,它仅处理原始字节对流的读写。 FileIO子类RawIOBase为机器文件系统中的文件提供接口。

BufferedIOBase处理原始字节流(RawIOBase)上的缓冲。它的子类BufferedWriterBufferedReaderBufferedRWPair缓冲流是可读,可写的以及可读和可写的。 BufferedRandom为随机访问流提供了一个缓冲接口。 BytesIO是一个简单的内存字节流。

另一个IOBase子类TextIOBase处理其字节表示文本的流,并处理unicode字符串之间的编码和解码。 TextIOWrapper对其进行了扩展,它是一个缓冲文本接口,用于缓冲原始流(BufferedIOBase)。最后,StringIO是 unicode 文本的内存流。

参数名称不是规范的一部分,仅open()的参数打算用作关键字参数。

15.2.1. 模块接口

Character Meaning
'r' 打开以供阅读(默认)
'w' 打开进行写入,先截断文件
'a' 打开进行写入,如果存在则追加到文件末尾
'b' binary mode
't' Literals 模式(默认)
'+' 打开磁盘文件以进行更新(读取和写入)
'U' 通用换行模式(为了向后兼容;不应在新代码中使用)

默认模式为'rt'(打开以阅读文本)。对于二进制随机访问,模式'w+b'将打开文件并将其截断为 0 字节,而'r+b'将打开文件而不会截断。

Python 区分以二进制和文本模式打开的文件,即使底层 os 没有。以二进制模式打开的文件(包括* mode 参数中的'b')以bytes对象的形式返回内容,而没有进行任何解码。在文本模式下(默认模式,或者当 mode 参数中包含't'时),文件的内容以unicode个字符串的形式返回,这些字节首先使用平台相关的编码或使用指定的 encoding *进行解码如果给出的话。

如果* closefd False并且给出了文件 Descriptors 而不是文件名,则在关闭文件时,底层文件 Descriptors 将保持打开状态。如果给定文件名, closefd *无效,并且必须为True(默认值)。

open()函数返回的文件对象的类型取决于模式。当使用open()以文本模式('w''r''wt''rt'等)打开文件时,它将返回TextIOBase的子类(特别是TextIOWrapper)。当使用带缓冲的二进制模式打开文件时,返回的类是BufferedIOBase的子类。确切的类有所不同:在读取二进制模式下,它返回BufferedReader;在写二进制和追加二进制模式下,它返回BufferedWriter,而在读/写模式下,它返回BufferedRandom。禁用缓冲后,将返回原始流RawIOBaseFileIO的子类。

也可以使用unicodebytes字符串作为文件进行读取和写入。对于unicode字符串StringIO可以像在文本模式下打开的文件一样使用,对于bytes BytesIO可以像在二进制模式下打开的文件一样使用。

除了IOError之外,BlockingIOError还具有一个属性:

15.2.2. I/O 基本类别

此类为派生类可以有选择地覆盖的许多方法提供了空的抽象实现。默认实现表示无法读取,写入或查找的文件。

尽管IOBase不会语句read()readinto()write(),因为它们的签名会有所不同,但实现和 Client 端应将这些方法视为接口的一部分。此外,在调用不支持的操作时,实现可能会引发IOError

用于从文件读取或写入文件的二进制数据的基本类型是bytes(也称为str)。方法参数也可以是字节数组的bytearraymemoryview。在某些情况下,例如readinto(),需要一个可写对象,例如bytearray。文本 I/O 类可处理unicode数据。

在 2.7 版中进行了更改:实现应支持memoryview参数。

请注意,在关闭的流上调用任何方法(甚至查询)都是未定义的。在这种情况下,实现可能会引发IOError

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

IOBase 还是上下文 Management 器,因此支持with语句。在此示例中,* file *在with语句的套件完成后关闭-即使发生异常:

with io.open('spam.txt', 'w') as file:
    file.write(u'Spam and eggs!')

IOBase提供了以下数据属性和方法:

为方便起见,允许多次调用此方法。但是,只有第一个电话才会生效。

对于二进制文件,行终止符始终为b'\n';对于文本文件,open()的* newline *参数可用于选择识别的行终止符。

请注意,已经可以使用for line in file: ...迭代文件对象而无需调用file.readlines()

返回新的绝对位置。

2.7 版的新Function:SEEK_*常量

原始二进制 I/O 通常提供对底层 OS 设备或 API 的低级别访问,并且不会try将其封装在高级基元中(这留给了缓冲 I/O 和文本 I/O,稍后将在本文档中进行介绍)页)。

除了IOBase的属性和方法外,RawIOBase 还提供以下方法:

如果返回 0 个字节,并且* n *不为 0,则表明文件结束。如果对象处于非阻塞模式并且没有字节可用,则返回None

RawIOBase的主要区别在于,方法read()readinto()write()会(分别)try读取请求的任意数量的 Importing 或消耗所有给定的输出,但以进行多个系统调用为代价。

另外,如果基础原始流处于非阻塞模式并且无法获取或提供足够的数据,则这些方法可以引发BlockingIOError;与他们的RawIOBase同行不同,他们永远不会返回None

此外,read()方法没有默认实现readinto()

典型的BufferedIOBase实现不应继承自RawIOBase实现,而应像BufferedWriterBufferedReader那样包装一个。

BufferedIOBase除了提供IOBase中的方法和属性外,还提供或覆盖这些方法和属性:

分离原始流后,缓冲区处于不可用状态。

某些缓冲区(例如BytesIO)没有从该方法返回单个原始流的概念。他们加注UnsupportedOperation

2.7 版的新Function。

如果参数为正,并且基础原始流不是交互式的,则可以发出多个原始读取来满足字节数(除非先到达 EOF)。但是对于交互式原始流,最多将发出一个原始读取,并且简短的结果并不意味着即将发生 EOF。

如果基础原始流处于非阻塞模式,并且此时没有可用数据,则引发BlockingIOError

read()一样,可以对基础原始流进行多次读取,除非后者是“交互式的”。

如果基础原始流处于非阻塞模式,并且此时没有可用数据,则引发BlockingIOError

在非阻塞模式下,如果需要将数据写入原始流,则它会引发BlockingIOError,但是如果不阻塞就无法接受所有数据。

在此方法返回之后,调用者可以释放或更改* b ,因此实现应仅在方法调用期间访问 b *。

15.2.3. 原始文件 I/O

模式可以是'r''w''a',用于读取(默认),写入或附加。如果在打开以进行写入或追加时不存在该文件,则将创建该文件;打开书写时将被截断。将'+'添加到该模式以允许同时读取和写入。

此类上的read()(使用正参数调用时),readinto()write()方法将仅进行一次系统调用。

除了IOBaseRawIOBase的属性和方法,FileIO还提供以下数据属性和方法:

15.2.4. 缓冲流

与原始 I/O 相比,缓冲的 I/O 流为 I/O 设备提供了更高级别的接口。

可选参数* initial_bytes *是包含初始数据的bytes对象。

BytesIO除了BufferedIOBaseIOBase中的方法外,还提供或覆盖了这些方法:

构造函数为给定的可读* raw 流和 buffer_size 创建一个BufferedReader。如果Ellipsis buffer_size *,则使用DEFAULT_BUFFER_SIZE

BufferedReader除了BufferedIOBaseIOBase中的方法外,还提供或覆盖了这些方法:

构造函数为给定的可写* raw 流创建一个BufferedWriter。如果未指定 buffer_size *,则默认为DEFAULT_BUFFER_SIZE

支持第三个参数* max_buffer_size *,但未使用且已弃用。

BufferedWriter除了BufferedIOBaseIOBase中的方法外,还提供或覆盖了这些方法:

构造函数为第一个参数中给出的可搜索原始流创建一个读取器和写入器。如果Ellipsis* buffer_size *,则默认为DEFAULT_BUFFER_SIZE

支持第三个参数* max_buffer_size *,但未使用且已弃用。

BufferedRandom具备BufferedReaderBufferedWriter可以做的任何事情。

支持第四个参数* max_buffer_size *,但未使用且已弃用。

BufferedRWPair实现BufferedIOBase的所有方法,但detach()引发UnsupportedOperation除外。

Warning

BufferedRWPair不会try同步对其基础原始流的访问。您不应将其与读写器传递给同Pair象;请改用BufferedRandom

15.2.5. LiteralsImporting/输出

TextIOBase除了提供IOBase中的数据属性和方法外,还提供或覆盖这些数据属性和方法:

分离基础缓冲区后,TextIOBase处于不可用状态。

某些TextIOBase实现(例如StringIO)可能没有底层缓冲区的概念,调用此方法将引发UnsupportedOperation

2.7 版的新Function。

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

返回新的绝对位置作为不透明数字。

2.7 版的新Function:SEEK_*常量。

如果* line_buffering *为True,则在写调用包含换行符或回车符时隐含flush()

TextIOWrapper除了TextIOBase及其父项之外,还提供了一个属性:

可以pass提供* initial_value *来设置缓冲区的初始值。如果启用了换行翻译,则换行将被编码为write()。流位于缓冲区的开头。

StringIO除了TextIOWrapper及其父级提供的方法外,还提供了此方法:

Example usage:

import io

output = io.StringIO()
output.write(u'First line.\n')
output.write(u'Second line.\n')

# Retrieve file contents -- this will be
# u'First line.\nSecond line.\n'
contents = output.getvalue()

# Close object and discard memory buffer --
# .getvalue() will now raise an exception.
output.close()

15.2.6. 进阶主题

在这里,我们将讨论与上述具体 I/O 实现有关的几个高级主题。

15.2.6.1. Performance

15.2.6.1.1. 二进制 I/O

pass即使在用户要求单个字节时也仅读取和写入大块数据,缓冲的 I/O 旨在隐藏调用和执行 os 的非缓冲 I/O 例程时的任何低效率。增益的变化取决于 os 和执行的 I/O 种类(例如,在某些现代的 OS(例如 Linux)上,未缓冲的磁盘 I/O 可以与缓冲的 I/O 一样快)。最重要的是,无论平台和支持设备如何,缓冲的 I/O 都能为您提供可预测的性能。因此,最总是最好使用缓冲 I/O 而不是未缓冲 I/O。

15.2.6.1.2. LiteralsImporting/输出

二进制存储(例如文件)上的文本 I/O 比相同存储上的二进制 I/O 显着慢,因为这意味着使用字符编解码器从 Unicode 转换为二进制数据。如果您处理大量文本数据(例如,非常大的日志文件),这可能会变得很明显。同样,由于使用了重建算法,TextIOWrapper.tell()TextIOWrapper.seek()都非常慢。

StringIO是内存中的本地 unicode 容器,其显示速度与BytesIO类似。

15.2.6.2. Multi-threading

FileIO对象是线程安全的,以至于它们包装的 os 调用(例如 Unix 下的read(2))也是线程安全的。

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

TextIOWrapper对象不是线程安全的。

15.2.6.3. Reentrancy

二进制缓冲对象(实例BufferedReaderBufferedWriterBufferedRandomBufferedRWPair)不可重入。虽然在正常情况下不会发生可重入调用,但是如果您在signal处理程序中执行 I/O,则可能会发生重调用。如果试图从同一个线程访问*时再次 Importing 一个缓冲对象,则会引发RuntimeError

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

首页