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

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

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.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:

美国广播公司 继承 存根方法 Mixin 方法和属性
IOBase filenoseektruncate closeclosed__enter____exit__flushisatty__iter__、[ X77X]、readablereadlinereadlinesseekabletellwritable X166X]
RawIOBase IOBase readintowrite 继承了 IOBase 方法、readreadall
BufferedIOBase IOBase detachreadread1write 继承了 IOBase 方法、readintoreadinto1
TextIOBase IOBase detachreadreadlinewrite 继承了 IOBase 方法、encodingerrorsnewlines

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 语句。 在这个例子中,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 相对于 wherece 指示的位置进行解释。 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 通常提供对底层 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 实现,而是包装一个,就像 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)

将字节读入预先分配的、可写的 字节类对象 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 版更改: 该文件现在不可继承。

除了来自 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

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

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 除了来自 BufferedIOBaseIOBase 的方法之外,还提供或覆盖这些方法:

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 除了来自 BufferedIOBaseIOBase 的方法之外,还提供或覆盖这些方法:

flush()

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

write(b)

写入bytes-like object,b,返回写入的字节数。 在非阻塞模式下,如果需要写出缓冲区但原始流阻塞,则会引发 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 实现了所有 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_SET0:从流开始寻找(默认); offset 必须是 TextIOBase.tell() 返回的数字,或者为零。 任何其他 offset 值都会产生未定义的行为。

  • SEEK_CUR1:“寻找”到当前位置; 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 是一个可选字符串,指定如何处理编码和解码错误。 如果存在编码错误,则通过 'strict' 引发 ValueError 异常(默认 None 具有相同效果),或通过 '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,则当 write 调用包含换行符或回车符时,隐含 flush()

如果 write_throughTrue,则保证不会缓冲对 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))也是线程安全的。

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

TextIOWrapper 对象不是线程安全的。


16.2.4.4. 重入性

二进制缓冲对象(BufferedReaderBufferedWriterBufferedRandomBufferedRWPair 的实例)不可重入。 虽然在正常情况下不会发生可重入调用,但在 信号 处理程序中执行 I/O 时可能会发生重入调用。 如果一个线程试图重新进入它已经访问的缓冲对象,则会引发 RuntimeError。 请注意,这不会禁止其他线程进入缓冲对象。

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