Skip to main content

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() 方法。

在 3.3 版更改: 以前用来提高 IOError 的操作现在提高了 OSError,因为 IOError 现在是 OSError 的别名。

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.1.3. 原始I/O

原始I/O(也称为 无缓冲I/O)通常用作二进制和文本流的低级构建块;它很少用于直接操作来自用户代码的原始流。不过,您可以通过在缓冲禁用的情况下以二进制模式打开文件来创建原始流:

f = open("myfile.jpg", "rb", buffering=0)

原始流API在 RawIOBase 的文档中详细描述。

16.2.2. 高级模块接口

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, opener=None)

这是内置 open() 函数的别名。

exception io.BlockingIOError

这是内置 BlockingIOError 异常的兼容性别名。

exception io.UnsupportedOperation

当在流上调用不受支持的操作时引发的 OSErrorValueError 的继承异常。

16.2.2.1. 内存流

也可以使用 strbytes-like object 作为用于读取和写入的文件。对于字符串 StringIO 可以像在文本模式下打开的文件一样使用。 BytesIO 可以像在二进制模式下打开的文件一样使用。两者都提供随机存取的完全读写能力。

参见

sys

包含标准IO流:sys.stdinsys.stdoutsys.stderr

16.2.3. 类层次结构

I/O流的实现被组织为类的层次结构。第一 抽象基类 (ABC),用于指定流的各种类别,然后具体类提供标准流实现。

注解

抽象基类还提供了一些方法的默认实现,以帮助实现具体的流类。例如,BufferedIOBase 提供 readinto()readline() 的未优化实现。

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

RawIOBase ABC延伸 IOBase。它处理字节读取和写入流。 FileIO 子类 RawIOBase 为机器文件系统中的文件提供接口。

BufferedIOBase ABC处理原始字节流(RawIOBase)上的缓冲。其子类,BufferedWriterBufferedReaderBufferedRWPair 缓冲区流,可读,可写,并且可读和可写。 BufferedRandom 向随机存取流提供缓冲接口。另一个 BufferedIOBase 子类,BytesIO,是一个内存中字节流。

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

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

下表总结了 io 模块提供的ABC:

ABC

继承

存根方法

Mixin方法和属性

IOBase

 

filenoseektruncate

closeclosed__enter____exit__flushisatty__iter____next__readablereadlinereadlinesseekabletellwritablewritelines

RawIOBase

IOBase

readintowrite

继承 IOBase 方法,readreadall

BufferedIOBase

IOBase

detachreadread1write

继承 IOBase 方法,readinto

TextIOBase

IOBase

detachreadreadlinewrite

继承 IOBase 方法,encodingerrorsnewlines

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 语句。在这个例子中,filewith 语句套件完成后关闭 - 即使发生异常:

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,如果流可以从中读取。如果 Falseread() 会升高 OSError

readline(size=-1)

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

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

readlines(hint=-1)

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

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

seek(offset[, whence])

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

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

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

  • SEEK_END2 - 流的结束; offset 通常为阴性

返回新的绝对位置。

3.1 新版功能: SEEK_* 常数。

3.3 新版功能: 一些操作系统可以支持附加值,例如 os.SEEK_HOLEos.SEEK_DATA。文件的有效值可能取决于它是以文本还是二进制模式打开。

seekable()

如果流支持随机访问,则返回 True。如果 Falseseek()tell()truncate() 将产生 OSError

tell()

返回当前流位置。

truncate(size=None)

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

在 3.5 版更改: 扩展时,Windows现在将填充文件。

writable()

如果流支持写入,则返回 True。如果 Falsewrite()truncate() 将提高 OSError

writelines(lines)

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

__del__()

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

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 objectb 写入基础原始流,并返回写入的字节数。这可以小于以字节为单位的 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

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 objectb,并返回写入的字节数(总是等于 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 来使用自定义打开程序。然后通过使用(nameflags)调用 opener 来获取文件对象的基础文件描述符。 opener 必须返回一个打开的文件描述符(传递 os.open 作为 opener 导致类似于传递 None 的功能)。

新创建的文件是 不可继承

有关使用 opener 参数的示例,请参阅 open() 内置函数。

在 3.3 版更改: 添加了 opener 参数。添加 'x' 模式。

在 3.4 版更改: 该文件现在是不可继承的。

除了来自 IOBaseRawIOBase 的属性和方法之外,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

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

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

除了来自 BufferedIOBaseIOBaseBufferedReader 之外,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

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

flush()

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

write(b)

写入 bytes-like objectb,并返回写入的字节数。当处于非阻塞模式时,如果缓冲区需要被写出而原始流被阻塞,则引发 BlockingIOError

class io.BufferedRandom(raw, buffer_size=DEFAULT_BUFFER_SIZE)

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

构造函数为第一个参数中给出的可寻找的原始流创建一个读写器。如果省略 buffer_size,它默认为 DEFAULT_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

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 新版功能.

read(size)

从流中读取并返回大多数 size 字符作为单个 str。如果 size 是阴性或 None,读取直到EOF。

readline(size=-1)

阅读直到换行或EOF并返回单个 str。如果流已经处于EOF,则返回一个空字符串。

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

seek(offset[, whence])

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

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

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

  • SEEK_END2:寻找到流的结尾; 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'。它的工作原理如下:

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

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

如果 line_bufferingTrue,则当写入调用包含换行符时,暗示 flush()

如果 write_throughTrue,则保证对 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 及其父母的方法之外还提供这种方法:

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

用于解码 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() 都相当缓慢。

然而,StringIO 是一个原生的内存中的unicode容器,并将表现出与 BytesIO 类似的速度。

16.2.4.3. 多线程

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

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

TextIOWrapper 对象不是线程安全的。

16.2.4.4. 再入

二进制缓冲对象(BufferedReaderBufferedWriterBufferedRandomBufferedRWPair 的实例)不可重入。虽然可重入调用在正常情况下不会发生,但它们可能来自于在 signal 处理程序中执行I/O。如果线程试图重新输入它已经访问的缓冲对象,则引发 RuntimeError。注意,这并不禁止不同的线程进入缓冲对象。

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