io - 用于处理流的核心工具

源代码: Lib/io.py


概述

io 模块提供了 Python 处理各种 I/O 的主要工具。I/O 主要有三种类型:*文本 I/O*、*二进制 I/O* 和 *原始 I/O*。这些是通用类别,每种类别都可以使用各种后备存储。属于这些类别中的任何一个的具体对象称为 文件对象。其他常用术语是 *流* 和 *类文件对象*。

每个具体的流对象,无论属于哪个类别,都具有一些功能:它可以是只读的、只写的,或者可读写的。它还可以允许任意随机访问(向前或向后查找任何位置),或者只允许顺序访问(例如在套接字或管道的情况下)。

所有流都非常注意你提供给它们的数据类型。例如,将一个 str 对象传递给二进制流的 write() 方法将引发 TypeError。将一个 bytes 对象传递给文本流的 write() 方法也会引发 TypeError

在 3.3 版更改: 以前引发 IOError 的操作现在引发 OSError,因为 IOError 现在是 OSError 的别名。

文本 I/O

文本 I/O 期望并生成 str 对象。这意味着,只要后备存储本身是由字节组成的(例如在文件的情况下),数据的编码和解码以及平台特定的换行符的可选转换都是透明地进行的。

创建文本流最简单的方法是使用 open(),并可选地指定编码

f = open("myfile.txt", "r", encoding="utf-8")

内存中文本流也可以作为 StringIO 对象使用

f = io.StringIO("some initial text data")

文本流 API 的详细说明请参阅 TextIOBase 的文档。

二进制 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()

原始 I/O

原始 I/O(也称为 *无缓冲 I/O*)通常用作二进制和文本流的底层构建块;直接从用户代码操作原始流很少有用。但是,你可以通过在禁用缓冲的情况下以二进制模式打开文件来创建原始流

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

原始流 API 的详细说明请参阅 RawIOBase 的文档。

文本编码

TextIOWrapperopen() 的默认编码是特定于区域设置的 (locale.getencoding())。

但是,许多开发人员在打开以 UTF-8 编码的文本文件(例如 JSON、TOML、Markdown 等)时忘记指定编码,因为大多数 Unix 平台默认使用 UTF-8 区域设置。这会导致错误,因为对于大多数 Windows 用户来说,区域设置编码不是 UTF-8。例如

# May not work on Windows when non-ASCII characters in the file.
with open("README.md") as f:
    long_description = f.read()

因此,强烈建议你在打开文本文件时明确指定编码。如果要使用 UTF-8,请传递 encoding="utf-8"。要使用当前的区域设置编码,从 Python 3.10 开始支持 encoding="locale"

另请参阅

Python UTF-8 模式

Python UTF-8 模式可用于将默认编码从特定于区域设置的编码更改为 UTF-8。

PEP 686

Python 3.15 将默认使用 Python UTF-8 模式

可选的 EncodingWarning

3.10 版新增: 有关详细信息,请参阅 PEP 597

要查找使用默认区域设置编码的位置,可以启用 -X warn_default_encoding 命令行选项或设置 PYTHONWARNDEFAULTENCODING 环境变量,这将在使用默认编码时发出 EncodingWarning

如果你提供的 API 使用 open()TextIOWrapper 并传递 encoding=None 作为参数,则可以使用 text_encoding(),以便 API 的调用者在未传递 encoding 时发出 EncodingWarning。但是,请考虑为新 API 默认使用 UTF-8(即 encoding="utf-8")。

高级模块接口

io.DEFAULT_BUFFER_SIZE

一个包含模块的缓冲 I/O 类使用的默认缓冲区大小的整型。如果可能,open() 会使用文件的 blksize(通过 os.stat() 获取)。

io.open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

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

此函数会使用参数 pathmodeflags 引发 审计事件 openmodeflags 参数可能已从原始调用中修改或推断出来。

io.open_code(path)

'rb' 模式打开提供的文件。当意图是将内容视为可执行代码时,应该使用此函数。

path 应该是一个 str 和一个绝对路径。

此函数的行为可能会被先前对 PyFile_SetOpenCodeHook() 的调用覆盖。但是,假设 path 是一个 str 和一个绝对路径,open_code(path) 的行为应该始终与 open(path, 'rb') 相同。覆盖此行为的目的是为了对文件进行额外的验证或预处理。

3.8 版新增。

io.text_encoding(encoding, stacklevel=2, /)

这是一个辅助函数,适用于使用 open()TextIOWrapper 并且具有 encoding=None 参数的可调用对象。

如果 encoding 不是 None,则此函数返回 encoding。否则,它会根据 UTF-8 模式 返回 "locale""utf-8"

如果 sys.flags.warn_default_encoding 为 true 并且 encodingNone,则此函数会发出 EncodingWarningstacklevel 指定发出警告的位置。例如

def read_text(path, encoding=None):
    encoding = io.text_encoding(encoding)  # stacklevel=2
    with open(path, encoding) as f:
        return f.read()

在此示例中,会为 read_text() 的调用方发出 EncodingWarning

有关更多信息,请参阅 文本编码

3.10 版新增。

在 3.11 版更改: 当启用 UTF-8 模式且 encodingNone 时,text_encoding() 返回“utf-8”。

异常 io.BlockingIOError

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

异常 io.UnsupportedOperation

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

另请参阅

sys

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

类层次结构

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

注意

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

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

RawIOBase 抽象基类继承自 IOBase。它处理字节流的读写操作。 FileIORawIOBase 的子类,用于提供访问机器文件系统中文件的接口。

BufferedIOBase 抽象基类继承自 IOBase。它处理原始二进制流 (RawIOBase) 的缓冲。它的子类 BufferedWriterBufferedReaderBufferedRWPair 分别缓冲可写、可读以及可读可写的原始二进制流。 BufferedRandom 为可查找流提供了一个缓冲接口。另一个 BufferedIOBase 子类 BytesIO 是一个内存字节流。

TextIOBase 抽象基类继承自 IOBase。它处理字节表示文本的流,并处理字符串的编码和解码。 TextIOWrapper 继承自 TextIOBase,它是一个用于缓冲原始流 (BufferedIOBase) 的缓冲文本接口。最后,StringIO 是一个用于文本的内存流。

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

下表总结了 io 模块提供的抽象基类

抽象基类

继承

存根方法

混合方法和属性

IOBase

filenoseektruncate

closeclosed__enter____exit__flushisatty__iter____next__readablereadlinereadlinesseekabletellwritablewritelines

RawIOBase

IOBase

readintowrite

继承自 IOBase 的方法,readreadall

BufferedIOBase

IOBase

detachreadread1write

继承自 IOBase 的方法,readintoreadinto1

TextIOBase

IOBase

detachreadreadlinewrite

继承自 IOBase 的方法,encodingerrorsnewlines

I/O 基类

class io.IOBase

所有 I/O 类的抽象基类。

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

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

从文件读取或写入文件的二进制数据的基本类型是 bytes。其他 类字节对象 也被接受作为方法参数。文本 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*,则不会再读取任何行。

*hint* 值为 0 或更小,以及 None,都被视为无提示。

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

seek(offset, whence=os.SEEK_SET, /)

将流位置更改为给定的字节 *offset*,该偏移量相对于 *whence* 指示的位置进行解释,并返回新的绝对位置。*whence* 的值如下:

  • os.SEEK_SET0 – 流的开头(默认值);*offset* 应为零或正数

  • os.SEEK_CUR1 – 当前流位置;*offset* 可以为负数

  • os.SEEK_END2 – 流的结尾;*offset* 通常为负数

3.1 版新增: SEEK_* 常量。

3.3 版新增: 一些操作系统可能支持其他值,例如 os.SEEK_HOLEos.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, /)

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

__del__()

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

class io.RawIOBase

原始二进制流的基类。它继承自 IOBase

原始二进制流通常提供对底层操作系统设备或 API 的低级访问,并且不会尝试将其封装在高级原语中(此功能在缓冲二进制流和文本流中以更高级别完成,本页稍后将对此进行描述)。

RawIOBase 除了提供 IOBase 中的方法外,还提供以下方法

read(size=-1, /)

从对象中读取最多 *size* 个字节并返回它们。为方便起见,如果未指定 *size* 或为 -1,则返回直到 EOF 的所有字节。否则,只进行一次系统调用。如果操作系统调用返回的字节数少于 *size* 个字节,则返回的字节数可能少于 *size* 个字节。

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

默认实现推迟到 readall()readinto()

readall()

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

readinto(b, /)

将字节读入预先分配的可写 类字节对象 *b* 中,并返回读取的字节数。例如,*b* 可能是一个 bytearray。如果对象处于非阻塞模式并且没有可用字节,则返回 None

write(b, /)

将给定的 类字节对象 *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 对象之上实现自己的缓冲,这将非常有用。

如果 size-1(默认值),则返回任意数量的字节(除非到达 EOF,否则大于零)。

readinto(b, /)

将字节读入预先分配的可写 类字节对象 b 并返回读取的字节数。例如,b 可能是一个 bytearray

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

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

readinto1(b, /)

将字节读入预先分配的可写 类字节对象 b,最多调用一次底层原始流的 read()(或 readinto())方法。返回读取的字节数。

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

3.5 版新增。

write(b, /)

写入给定的 类字节对象 b,并返回写入的字节数(始终等于 b 的字节长度,因为如果写入失败,将引发 OSError)。根据实际的实现,这些字节可能会立即写入底层流,或者为了性能和延迟原因保存在缓冲区中。

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

调用者可以在此方法返回后释放或改变 b,因此实现应该只在此方法调用期间访问 b

原始文件 I/O

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

表示包含字节数据的操作系统级文件的原始二进制流。它继承自 RawIOBase

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 版更改: 该文件现在不可继承。

FileIO 除了提供 RawIOBaseIOBase 中的数据属性外,还提供以下数据属性

mode

构造函数中给出的模式。

name

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

缓冲流

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

class io.BytesIO(initial_bytes=b'')

使用内存中字节缓冲区的二进制流。它继承自 BufferedIOBase。调用 close() 方法时,缓冲区将被丢弃。

可选参数 initial_bytes 是一个包含初始数据的 类字节对象

除了 BufferedIOBaseIOBase 中的方法外,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(size=-1, /)

BytesIO 中,这与 read() 相同。

3.7 版更改: size 参数现在是可选的。

readinto1(b, /)

BytesIO 中,这与 readinto() 相同。

3.5 版新增。

class io.BufferedReader(raw, buffer_size=DEFAULT_BUFFER_SIZE)

一个缓冲二进制流,为可读、不可查找的 RawIOBase 原始二进制流提供更高级别的访问。它继承自 BufferedIOBase

从此对象读取数据时,可能会从底层原始流请求更多数据,并将其保存在内部缓冲区中。然后,可以在后续读取时直接返回缓冲数据。

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

除了 BufferedIOBaseIOBase 中的方法外,BufferedReader 还提供或重写了以下方法

peek(size=0, /)

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

read(size=-1, /)

读取并返回 size 个字节,如果未给出 size 或为负数,则读取到 EOF 或在非阻塞模式下读取调用将阻塞为止。

read1(size=-1, /)

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

3.7 版更改: size 参数现在是可选的。

class io.BufferedWriter(raw, buffer_size=DEFAULT_BUFFER_SIZE)

一个缓冲二进制流,提供对可写、不可查找的 RawIOBase 原始二进制流的更高级别访问。它继承自 BufferedIOBase

写入此对象时,数据通常会被放入内部缓冲区。缓冲区将在各种情况下被写入底层的 RawIOBase 对象,包括

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

BufferedWriter 提供或覆盖了 BufferedIOBaseIOBase 中的方法之外的以下方法

flush()

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

write(b, /)

写入 类字节对象 b,并返回写入的字节数。在非阻塞模式下,如果需要写入缓冲区但原始流阻塞,则会引发 BlockingIOError

class io.BufferedRandom(raw, buffer_size=DEFAULT_BUFFER_SIZE)

一个缓冲二进制流,提供对可查找的 RawIOBase 原始二进制流的更高级别访问。它继承自 BufferedReaderBufferedWriter

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

BufferedRandom 能够执行 BufferedReaderBufferedWriter 可以执行的任何操作。此外,保证实现了 seek()tell()

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

一个缓冲二进制流,提供对两个不可查找的 RawIOBase 原始二进制流的更高级别访问——一个可读,另一个可写。它继承自 BufferedIOBase

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

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

警告

BufferedRWPair 不会尝试同步对其底层原始流的访问。您不应该将同一个对象作为读取器和写入器传递给它;请改用 BufferedRandom

文本 I/O

class io.TextIOBase

文本流的基类。此类为流 I/O 提供了基于字符和行的接口。它继承自 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=SEEK_SET, /)

将流位置更改为给定的 *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.getencoding()。可以使用 encoding="locale" 显式指定当前区域设置的编码。有关更多信息,请参阅 文本编码

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

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

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

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

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

如果 write_throughTrue,则保证对 write() 的调用不会被缓冲:写入 TextIOWrapper 对象的任何数据都会立即被处理到其底层的二进制 buffer

版本 3.3 中的变化: 添加了 write_through 参数。

版本 3.3 中的变化: 默认 encoding 现在是 locale.getpreferredencoding(False) 而不是 locale.getpreferredencoding()。不要使用 locale.setlocale() 临时更改区域设置编码,而是使用当前区域设置编码而不是用户首选编码。

版本 3.10 中的变化: encoding 参数现在支持 "locale" 虚拟编码名称。

TextIOWrapper 除了提供 TextIOBaseIOBase 中的数据属性和方法外,还提供以下数据属性和方法:

line_buffering

是否启用了行缓冲。

write_through

写入是否立即传递到底层的二进制缓冲区。

3.7 版新增。

reconfigure(*, encoding=None, errors=None, newline=None, line_buffering=None, write_through=None)

使用 encodingerrorsnewlineline_bufferingwrite_through 的新设置重新配置此文本流。

未指定的参数将保留当前设置,但当指定了 encoding 但未指定 errors 时,将使用 errors='strict'

如果已经从流中读取了一些数据,则无法更改编码或换行符。另一方面,在写入后更改编码是可能的。

此方法在设置新参数之前执行隐式流刷新。

3.7 版新增。

版本 3.11 中的变化: 该方法支持 encoding="locale" 选项。

seek(cookie, whence=os.SEEK_SET, /)

设置流位置。将新的流位置作为 int 返回。

支持四种操作,由以下参数组合给出:

  • seek(0, SEEK_SET):倒回到流的开头。

  • seek(cookie, SEEK_SET):恢复到之前的位置;cookie 必须tell() 返回的数字。

  • seek(0, SEEK_END):快进到流的末尾。

  • seek(0, SEEK_CUR):保持当前流位置不变。

任何其他参数组合都是无效的,并且可能会引发异常。

另请参阅

os.SEEK_SETos.SEEK_CURos.SEEK_END

tell()

以不透明数字的形式返回流位置。tell() 的返回值可以作为输入提供给 seek(),以恢复到之前的流位置。

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

使用内存中文本缓冲区的文本流。它继承自 TextIOBase

当调用 close() 方法时,文本缓冲区将被丢弃。

可以通过提供 initial_value 来设置缓冲区的初始值。如果启用了换行符转换,则换行符将按照 write() 的方式进行编码。流位于缓冲区的开头,这模拟了在 w+ 模式下打开现有文件,使其准备好从头开始立即写入或覆盖初始值的写入。要模拟以 a+ 模式打开文件以进行追加,请使用 f.seek(0, io.SEEK_END) 将流重新定位到缓冲区的末尾。

newline 参数的工作方式与 TextIOWrapper 的工作方式相同,不同之处在于,在将输出写入流时,如果 newlineNone,则换行符在所有平台上都将写入为 \n

StringIO 除了提供 TextIOBaseIOBase 中的方法外,还提供了以下方法

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

性能

本节讨论提供的具体 I/O 实现的性能。

二进制 I/O

通过仅读取和写入大块数据(即使用户请求单个字节),缓冲 I/O 隐藏了调用和执行操作系统无缓冲 I/O 例程的任何低效率。增益取决于操作系统和执行的 I/O 类型。例如,在某些现代操作系统(如 Linux)上,无缓冲磁盘 I/O 的速度可以与缓冲 I/O 一样快。然而,底线是,无论平台和后备设备如何,缓冲 I/O 都能提供可预测的性能。因此,对于二进制数据,几乎总是最好使用缓冲 I/O 而不是无缓冲 I/O。

文本 I/O

二进制存储(如文件)上的文本 I/O 明显慢于相同存储上的二进制 I/O,因为它需要使用字符编解码器在 Unicode 和二进制数据之间进行转换。这在处理大量文本数据(如大型日志文件)时会变得很明显。此外,由于使用了重建算法,tell()seek() 都非常慢。

但是,StringIO 是一个原生的内存 Unicode 容器,其速度与 BytesIO 相似。

多线程

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

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

TextIOWrapper 对象不是线程安全的。

可重入性

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

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