15.2. io — 处理流的核心工具 — Python 文档

来自菜鸟教程
Python/docs/2.7/library/io
跳转至:导航、​搜索

15.2. io — 处理流的核心工具

2.6 版中的新功能。


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

笔记

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


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

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

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

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

参数名称不是规范的一部分,只有 open() 的参数旨在用作关键字参数。

15.2.1. 模块接口

io.DEFAULT_BUFFER_SIZE
一个 int 包含模块的缓冲 I/O 类使用的默认缓冲区大小。 open() 尽可能使用文件的 blksize(由 os.stat() 获得)。
io.open(file, mode='r', buffering=- 1, encoding=None, errors=None, newline=None, closefd=True)

打开 file 并返回相应的流。 如果无法打开文件,则会引发 IOError

file 是一个字符串,给出要打开的文件的路径名(绝对或相对于当前工作目录)或要包装的文件的整数文件描述符。 (如果给出了文件描述符,则在返回的 I/O 对象关闭时它也将关闭,除非 closefd 设置为 False。)

mode 是一个可选字符串,用于指定打开文件的模式。 默认为 'r',表示以文本模式打开阅读。 其他常见的值是 'w' 用于写入(如果文件已经存在则截断文件)和 'a' 用于追加(在 some Unix 系统上,意味着 all 将追加写入文件末尾,而不管当前查找位置如何)。 在文本模式下,如果未指定 encoding,则使用的编码取决于平台。 (对于读取和写入原始字节,请使用二进制模式并保留 encoding 未指定。)可用模式有:

特点

意义

'r'

开放阅读(默认)

'w'

打开写入,先截断文件

'a'

打开以进行写入,如果存在则附加到文件末尾

'b'

二进制模式

't'

文本模式(默认)

'+'

打开磁盘文件进行更新(读写)

'U'

通用换行模式(为了向后兼容;不应在新代码中使用)

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

Python 区分以二进制和文本模式打开的文件,即使底层操作系统没有。 以二进制模式打开的文件(包括 mode 参数中的 'b')将内容作为 bytes 对象返回,无需任何解码。 在文本模式下(默认情况下,或者当 't' 包含在 mode 参数中时),文件的内容作为 unicode 字符串返回,字节已被首先使用依赖于平台的编码或使用指定的 编码 (如果给定)进行解码。

buffering 是一个可选整数,用于设置缓冲策略。 传递 0 以关闭缓冲(仅在二进制模式下允许),1 以选择行缓冲(仅可用于文本模式),以及一个大于 1 的整数以指示固定大小块缓冲区的大小。 当没有给出 buffering 参数时,默认缓冲策略的工作方式如下:

  • 二进制文件以固定大小的块缓冲; 缓冲区的大小是使用试探法来选择的,尝试确定底层设备的“块大小”并回退到 DEFAULT_BUFFER_SIZE。 在许多系统上,缓冲区通常为 4096 或 8192 字节长。

  • “交互式”文本文件(isatty() 返回 True 的文件)使用行缓冲。 其他文本文件使用上述针对二进制文件的策略。

encoding 是用于解码或编码文件的编码名称。 这应该只在文本模式下使用。 默认编码取决于平台(无论 locale.getpreferredencoding() 返回什么),但可以使用 Python 支持的任何编码。 有关支持的编码列表,请参阅 codecs 模块。

errors 是一个可选字符串,指定如何处理编码和解码错误——这不能在二进制模式下使用。 如果存在编码错误,则通过 'strict' 引发 ValueError 异常(默认 None 具有相同效果),或通过 'ignore' 忽略错误. (请注意,忽略编码错误会导致数据丢失。) 'replace' 会导致替换标记(例如 '?')插入到格式错误的数据处。 写入时,可以使用 'xmlcharrefreplace'(替换为适当的 XML 字符引用)或 'backslashreplace'(替换为反斜杠转义序列)。 任何其他已用 codecs.register_error() 注册的错误处理名称也是有效的。

newline 控制 universal newlines 如何工作(它只适用于文本模式)。 它可以是 None'\n''\r''\r\n'。 它的工作原理如下:

  • 在输入时,如果 newlineNone,则启用通用换行模式。 输入中的行可以以 '\n''\r''\r\n' 结尾,这些在返回给调用者之前会被转换为 '\n'。 如果是 ,则启用通用换行符模式,但行尾未翻译返回给调用者。 如果它具有任何其他合法值,则输入行仅由给定的字符串终止,并且行尾未翻译地返回给调用者。

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

如果 closefdFalse 并且给出了文件描述符而不是文件名,则在文件关闭时底层文件描述符将保持打开状态。 如果给定文件名 closefd 没有效果,并且必须是 True(默认值)。

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

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

exception io.BlockingIOError

在非阻塞流上发生阻塞时引发错误。 它继承了IOError

除了 IOError 的那些,BlockingIOError 还有一个属性:

characters_written

一个整数,包含在阻塞之前写入流的字符数。

exception io.UnsupportedOperation
继承 IOErrorValueError 的异常,在对流调用不受支持的操作时引发。


15.2.2. I/O 基类

class io.IOBase

所有 I/O 类的抽象基类,作用于字节流。 没有公共构造函数。

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

即使 IOBase 没有声明 read()readinto()write(),因为它们的签名会有所不同,但实现和客户端应该将这些方法视为接口的一部分. 此外,当调用它们不支持的操作时,实现可能会引发 IOError

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

2.7 版更改: 实现应支持 memoryview 参数。

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

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

IOBase 也是一个上下文管理器,因此支持 with 语句。 在这个例子中,filewith 语句的套件完成后关闭——即使发生异常:

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

IOBase 提供了这些数据属性和方法:

close()

冲洗并关闭此流。 如果文件已经关闭,则此方法无效。 一旦文件关闭,对文件的任何操作(例如 读或写)将引发 ValueError

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

closed

如果流已关闭,则为真。

fileno()

如果存在,则返回流的底层文件描述符(整数)。 如果 IO 对象不使用文件描述符,则会引发 IOError

flush()

如果适用,刷新流的写入缓冲区。 这对只读和非阻塞流没有任何作用。

isatty()

如果流是交互式的(即连接到终端/tty 设备),则返回 True

readable()

如果可以读取流,则返回 True。 如果 Falseread() 将提升 IOError

readline(limit=- 1)

从流中读取并返回一行。 如果指定了 limit,则最多读取 limit 个字节。

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

readlines(hint=- 1)

从流中读取并返回行列表。 可以指定 hint 来控制读取的行数:如果到目前为止所有行的总大小(以字节/字符为单位)超过 hint,则不再读取行。

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

seek(offset, whence=SEEK_SET)

将流位置更改为给定字节 offsetoffset 相对于 wherece 指示的位置进行解释。 whence 的默认值为 SEEK_SETwhence 的值是:

  • SEEK_SET0 – 流的开始(默认); offset 应为零或正

  • SEEK_CUR1 – 当前流位置; offset 可能为负

  • SEEK_END2 – 流结束; offset 通常为负

返回新的绝对位置。

2.7 版新增:SEEK_* 常量

seekable()

如果流支持随机访问,则返回 True。 如果 Falseseek()tell()truncate() 将引发 IOError

tell()

返回当前流位置。

truncate(size=None)

以字节为单位将流调整为给定的 size(如果未指定 size,则为当前位置)。 当前流位置不会改变。 这种调整大小可以扩展或减少当前文件的大小。 在扩展的情况下,新文件区域的内容取决于平台(在大多数系统上,附加字节是零填充的,在 Windows 上它们是不确定的)。 返回新文件大小。

writable()

如果流支持写入,则返回 True。 如果 Falsewrite()truncate() 将引发 IOError

writelines(lines)

将行列表写入流。 没有添加行分隔符,因此通常提供的每行末尾都有一个行分隔符。

__del__()

准备对象销毁。 IOBase 提供了这个方法的默认实现,它调用实例的 close() 方法。

class io.RawIOBase

原始二进制 I/O 的基类。 它继承了IOBase。 没有公共构造函数。

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

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

read(n=- 1)

从对象中读取最多 n 个字节并返回它们。 为方便起见,如果 n 未指定或为 -1,则调用 readall()。 否则,只进行一次系统调用。 如果操作系统调用返回少于 n 个字节,则可能返回少于 n 个字节。

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

readall()

读取并返回流中的所有字节,直到 EOF,必要时使用对流的多次调用。

readinto(b)

将最多 len(b) 个字节读入 b,并返回读取的字节数。 对象 b 应该是一个预先分配的、可写的字节数组,可以是 bytearraymemoryview。 如果对象处于非阻塞模式并且没有可用字节,则返回 None

write(b)

b 写入底层原始流,并返回写入的字节数。 对象 b 应该是一个字节数组,可以是 bytesbytearraymemoryview。 返回值可以小于 len(b),具体取决于底层原始流的细节,尤其是在非阻塞模式下。 None。 此方法返回后,调用者可能会释放或变异 b,因此实现应仅在方法调用期间访问 b

class io.BufferedIOBase

支持某种缓冲的二进制流的基类。 它继承了IOBase。 没有公共构造函数。

RawIOBase 的主要区别在于方法 read()readinto()write() 将尝试(分别)读取尽可能多的输入或消耗所有给定的输出,代价是可能进行不止一个系统调用。

此外,如果底层原始流处于非阻塞模式并且无法获取或提供足够的数据,这些方法可能会引发 BlockingIOError; 与它们的 RawIOBase 对应物不同,它们永远不会返回 None

此外,read() 方法没有遵循 readinto() 的默认实现。

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

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

raw

BufferedIOBase 处理的底层原始流(RawIOBase 实例)。 这不是 BufferedIOBase API 的一部分,并且在某些实现中可能不存在。

detach()

将底层原始流与缓冲区分开并返回。

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

某些缓冲区,如 BytesIO,没有从该方法返回的单个原始流的概念。 他们提出 UnsupportedOperation

2.7 版中的新功能。

read(n=- 1)

读取并返回最多 n 个字节。 如果省略参数,None 或负数,则读取并返回数据,直到达到 EOF。 如果流已经处于 EOF,则返回一个空字节对象。

如果参数为正,并且底层原始流不是交互式的,则可能会发出多个原始读取以满足字节数(除非首先达到 EOF)。 但是对于交互式原始流,最多会发出一个原始读取,并且一个简短的结果并不意味着 EOF 迫在眉睫。

如果底层原始流处于非阻塞模式并且目前没有可用数据,则会引发 BlockingIOError

read1(n=- 1)

读取并返回最多 n 个字节,最多调用一次底层原始流的 read() 方法。 如果您在 BufferedIOBase 对象之上实现自己的缓冲,这会很有用。

readinto(b)

将最多 len(b) 个字节读入 b,并返回读取的字节数。 对象 b 应该是一个预先分配的、可写的字节数组,可以是 bytearraymemoryview

read() 一样,可以向底层原始流发出多次读取,除非后者是“交互式”的。

如果底层原始流处于非阻塞模式并且目前没有可用数据,则会引发 BlockingIOError

write(b)

写入 b,并返回写入的字节数(始终等于 len(b),因为如果写入失败,将引发 IOError)。 对象 b 应该是一个字节数组,可以是 bytesbytearraymemoryview。 根据实际实现,这些字节可以很容易地写入底层流,或者出于性能和延迟原因保存在缓冲区中。

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

此方法返回后,调用者可能会释放或变异 b,因此实现应仅在方法调用期间访问 b


15.2.3. 原始文件 I/O

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

FileIO 表示包含字节数据的操作系统级文件。 它实现了 RawIOBase 接口(因此也实现了 IOBase 接口)。

name 可以是以下两种情况之一:

  • 一个字符串,表示将要打开的文件的路径;

  • 一个整数,表示生成的 FileIO 对象将提供访问权限的现有操作系统级文件描述符的编号。

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

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

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

mode

构造函数中给出的模式。

name

文件名。 当构造函数中没有给出名称时,这是文件的文件描述符。


15.2.4. 缓冲流

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

class io.BytesIO([initial_bytes])

使用内存字节缓冲区的流实现。 它继承了 BufferedIOBase

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

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

getvalue()

返回包含缓冲区全部内容的 bytes

read1()

BytesIO 中,这与 read() 相同。

class io.BufferedReader(raw, buffer_size=DEFAULT_BUFFER_SIZE)

提供对可读、顺序 RawIOBase 对象的更高级别访问的缓冲区。 它继承了 BufferedIOBase。 从该对象读取数据时,可能会从底层原始流请求大量数据,并将其保存在内部缓冲区中。 然后可以在后续读取时直接返回缓冲数据。

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

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

peek([n])

从流中返回字节而不推进位置。 最多对原始流进行一次读取以满足调用。 返回的字节数可能比请求的少或多。

read([n])

读取并返回 n 字节,或者如果 n 未给出或为负,直到 EOF 或读取调用将在非阻塞模式下阻塞。

read1(n)

读取并返回最多 n 个字节,仅对原始流进行一次调用。 如果至少缓冲了一个字节,则只返回缓冲的字节。 否则,将进行一次原始流读取调用。

class io.BufferedWriter(raw, buffer_size=DEFAULT_BUFFER_SIZE)

提供对可写、顺序 RawIOBase 对象的更高级别访问的缓冲区。 它继承了 BufferedIOBase。 写入此对象时,数据通常保存在内部缓冲区中。 缓冲区将在各种条件下写入底层 RawIOBase 对象,包括:

  • 当缓冲区对于所有待处理数据来说太小时;

  • flush() 被调用时;

  • 当请求 seek() 时(对于 BufferedRandom 对象);

  • BufferedWriter 对象关闭或销毁时。

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

支持第三个参数 max_buffer_size,但未使用和弃用。

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

flush()

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

write(b)

写入b,返回写入的字节数。 对象 b 应该是一个字节数组,可以是 bytesbytearraymemoryview。 在非阻塞模式下,如果需要写出缓冲区但原始流阻塞,则会引发 BlockingIOError

class io.BufferedRandom(raw, buffer_size=DEFAULT_BUFFER_SIZE)

随机访问流的缓冲接口。 它继承了 BufferedReaderBufferedWriter,并进一步支持 seek()tell() 功能。

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

支持第三个参数 max_buffer_size,但未使用和弃用。

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

class io.BufferedRWPair(reader, writer, buffer_size=DEFAULT_BUFFER_SIZE)

一个缓冲的 I/O 对象将两个单向 RawIOBase 对象(一个可读,另一个可写)组合到一个双向端点中。 它继承了 BufferedIOBase

readerwriter 分别是可读和可写的 RawIOBase 对象。 如果省略 buffer_size,则默认为 DEFAULT_BUFFER_SIZE

支持第四个参数 max_buffer_size,但未使用和弃用。

BufferedRWPair 实现了所有 BufferedIOBase' 的方法,除了 detach(),它引发了 UnsupportedOperation

警告

BufferedRWPair 不会尝试同步对其底层原始流的访问。 您不应该将与 reader 和 writer 相同的对象传递给它; 改用 BufferedRandom


15.2.5. 文本输入/输出

class io.TextIOBase

文本流的基类。 此类提供了一个基于 Unicode 字符和行的接口来流 I/O。 没有 readinto() 方法,因为 Python 的 unicode 字符串是不可变的。 它继承了IOBase。 没有公共构造函数。

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

encoding

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

errors

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

newlines

一个字符串、一个字符串元组或 None,表示到目前为止翻译的换行符。 根据实现和初始构造函数标志,这可能不可用。

buffer

TextIOBase 处理的底层二进制缓冲区(一个 BufferedIOBase 实例)。 这不是 TextIOBase API 的一部分,在某些实现中可能不存在。

detach()

将底层二进制缓冲区与 TextIOBase 分开并返回。

底层缓冲区被分离后,TextIOBase 处于不可用状态。

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

2.7 版中的新功能。

read(n=- 1)

从流中读取并返回至多 n 个字符作为单个 unicode。 如果 n 为负数或 None,读取直到 EOF。

readline(limit=- 1)

读到换行符或 EOF 并返回一个 unicode。 如果流已经在 EOF,则返回一个空字符串。

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

seek(offset, whence=SEEK_SET)

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

  • SEEK_SET0:从流开始寻找(默认); offset 必须是 TextIOBase.tell() 返回的数字,或者为零。 任何其他 offset 值都会产生未定义的行为。

  • SEEK_CUR1:“寻找”到当前位置; offset 必须为零,这是一个无操作(不支持所有其他值)。

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

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

2.7 版新增:SEEK_* 常量。

tell()

将当前流位置作为不透明数字返回。 该数字通常不代表底层二进制存储中的字节数。

write(s)

unicode 字符串 s 写入流并返回写入的字符数。

class io.TextIOWrapper(buffer, encoding=None, errors=None, newline=None, line_buffering=False)

BufferedIOBase 二进制流上的缓冲文本流。 它继承了 TextIOBase

encoding 给出流将被解码或编码的编码名称。 它默认为 locale.getpreferredencoding()

errors 是一个可选字符串,指定如何处理编码和解码错误。 如果存在编码错误,则通过 'strict' 引发 ValueError 异常(默认 None 具有相同效果),或通过 'ignore' 忽略错误. (请注意,忽略编码错误会导致数据丢失。) 'replace' 会导致替换标记(例如 '?')被插入到格式错误的数据处。 写入时,可以使用 'xmlcharrefreplace'(替换为适当的 XML 字符引用)或 'backslashreplace'(替换为反斜杠转义序列)。 任何其他已用 codecs.register_error() 注册的错误处理名称也是有效的。

newline 控制如何处理行尾。 它可以是 None'\n''\r''\r\n'。 它的工作原理如下:

  • 在输入时,如果 newlineNone,则启用 universal newlines 模式。 输入中的行可以以 '\n''\r''\r\n' 结尾,这些在返回给调用者之前会被转换为 '\n'。 如果是 ,则启用通用换行符模式,但行尾未翻译返回给调用者。 如果它具有任何其他合法值,则输入行仅由给定的字符串终止,并且行尾未翻译地返回给调用者。

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

如果 line_bufferingTrue,则当 write 调用包含换行符或回车符时,隐含 flush()

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

line_buffering

是否启用行缓冲。

class io.StringIO(initial_value=, newline='\\n')

unicode 文本的内存流。 它继承了 TextIOWrapper

缓冲区的初始值可以通过提供 initial_value 来设置。 如果启用换行符转换,换行符将被编码为 write()。 流位于缓冲区的开头。

newline 参数的工作方式类似于 TextIOWrapper。 默认值是仅将 \n 字符视为行尾,并且不进行换行转换。 如果newline设置为None,所有平台的换行符都写为\n,但读取时仍然进行通用换行解码。

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

getvalue()

在调用 StringIO 对象的 close() 方法之前的任何时间返回一个 unicode 包含缓冲区的全部内容。 尽管流位置没有改变,但换行符的解码就像是 read()

用法示例:

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

class io.IncrementalNewlineDecoder
一个辅助编解码器,用于解码 通用换行符 模式的换行符。 它继承了 codecs.IncrementalDecoder


15.2.6. 进阶课题

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

15.2.6.1. 表现

15.2.6.1.1. 二进制输入/输出

通过即使在用户请求单个字节时也仅读取和写入大块数据,缓冲 I/O 旨在隐藏调用和执行操作系统的无缓冲 I/O 例程时的任何低效。 增益会因操作系统和执行的 I/O 类型而有很大差异(例如,在一些现代操作系统如 Linux 上,无缓冲磁盘 I/O 可以与缓冲 I/O 一样快)。 然而,最重要的是,无论平台和支持设备如何,缓冲 I/O 都将为您提供可预测的性能。 因此,最好使用缓冲 I/O 而不是非缓冲 I/O。


15.2.6.1.2. 文本输入/输出

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

然而,StringIO 是本机内存中的 unicode 容器,其速度与 BytesIO 相似。


15.2.6.2. 多线程

FileIO 对象是线程安全的,因为它们包装的操作系统调用(例如 Unix 下的 read(2))也是线程安全的。

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

TextIOWrapper 对象不是线程安全的。


15.2.6.3. 重入性

二进制缓冲对象(BufferedReaderBufferedWriterBufferedRandomBufferedRWPair 的实例)不可重入。 虽然在正常情况下不会发生可重入调用,但如果您在 信号 处理程序中执行 I/O,它们可能会出现。 如果在已从同一线程 访问 的情况下再次尝试进入缓冲对象,则会引发 RuntimeError

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