Python - io 模块

本文详细介绍了Python的io模块,包括文本I/O、二进制I/O和原始I/O,以及选择性的EncodingWarning,强调了指定文件编码的重要性。io模块提供核心的流处理工具,支持缓冲和不同类型的I/O流,如BufferedReader、BufferedWriter等。文章还提到了Python中处理文件的抽象基类和具体实现,以及与文件操作相关的异常。
摘要由CSDN通过智能技术生成


本文转载改编自: https://docs.python.org/zh-cn/3/library/io.html
在原文中有重新删减、编号、添加示例。


关于 io 模块

io 模块提供了 Python 用于处理各种 I/O 类型的主要工具。


三种主要的 I/O类型分别为:

  1. 文本 I/O
    文本IO所产生的是str对象,如果后备存储本身使用的是字节组成,可以通过编码和解码数据来适应平台数据类型。

  2. 二进制 I/O
    二进制IO也称为缓冲IO,需要类似字节的对象并生成bytes对象,不执行编码,解码或换行,这种类型的流可以用于非文本数据,并且还需要手动控制文本数据的处理。

  3. 原始 I/O
    原始I,也称为无缓冲IO。通常用作二进制和文本流的低级构建块。(一般不推荐使用)
    可从用户代码直接操作原始流,也可以通过在缓冲禁用的情况下 以二进制模式打开文件来创建原始流。


这些是泛型类型,有很多种后端存储可以用在他们上面。

一个隶属于任何这些类型的具体对象被称作 file object。
其他同类的术语还有 类文件对象

独立于其类别,每个具体流对象也将具有各种功能:它可以是只读,只写或读写。
它还可以允许任意随机访问(向前或向后寻找任何位置),或仅允许顺序访问(例如在套接字或管道的情况下)。

所有流对提供给它们的数据类型都很敏感。
例如将 str对象给二进制流的 write() 方法会引发 TypeError
bytes 对象提供给文本流的 write() 方法也是如此。

在 3.3 版更改: 由于 IOError 现在是 OSError 的别名,因此用于引发 IOError 的操作现在会引发 OSError


1、文本 I/O

文本I/O预期并生成 str 对象。
这意味着,无论何时后台存储是由字节组成的(例如在文件的情况下),数据的编码和解码都是透明的,并且可以选择转换特定于平台的换行符。

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

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

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

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

下方 TextIOBase 的文档中详细描述了文本流的API


2、二进制(字节) I/O

二进制I/O(也称为缓冲I/O)预期 bytes-like objects 并生成 bytes 对象。
不执行编码、解码或换行转换。
这种类型的流可以用于所有类型的非文本数据,并且还可以在需要手动控制文本数据的处理时使用。

创建二进制流的最简单方法是使用 open(),并在模式字符串中指定 b

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

内存中二进制流也可以作为 BytesIO 对象使用:

f = io.BytesIO(b"some initial binary data: \x00\x01")

下方 BufferedIOBase 的文档中详细描述了二进制流 API


其他库模块可以提供额外的方式来创建文本或二进制流。
参见 socket.socket.makefile() 的示例:http://study.yali.edu.cn/pythonhelp/library/socket.html#socket.socket.makefile


3、原始 I/O

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

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

RawIOBase 的文档中详细描述了原始流的API
http://study.yali.edu.cn/pythonhelp/library/io.html#io.RawIOBase


二、文本编码格式

TextIOWrapperopen() 的默认编码格式取决于语言区域设置 locale.getpreferredencoding(False) : http://study.yali.edu.cn/pythonhelp/library/locale.html#locale.getpreferredencoding.


但是,很多开发者在打开以 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()

此外,虽然暂时还没有确定的计划,但 Python 可能会在未来将默认的文本文件编码格式改为 UTF-8。

为此,强烈建议你在打开文本文件时显式地指定编码格式。
如果你想要使用 UTF-8,请传入 encoding="utf-8"
要使用当前语言区域的编码格式,encoding="locale" (已在 Python 3.10 中被支持)。


When you need to run existing code on Windows that attempts to open UTF-8 files using the default locale encoding, you can enable the UTF-8 mode. See UTF-8 mode on Windows:
http://study.yali.edu.cn/pythonhelp/using/windows.html#win-utf8-mode.


选择性的 EncodingWarning

3.10 新版功能: 请参阅 PEP 597 https://www.python.org/dev/peps/pep-0597

要找出哪里使用了默认语言区域的编码格式,你可以启用 -X warn_default_encoding 命令行选项或设置 PYTHONWARNDEFAULTENCODING 环境变量,这将在使用默认编码格式时发出 EncodingWarning

如果你提供了使用 open()TextIOWrapper 的 API 并将 encoding=None 作为形参传入,你可以使用 text_encoding() 以便 API 的调用方在没有传入 encoding 的时候将发出 EncodingWarning
但是,对于新的 API 请考虑默认就使用 UTF-8 (即 encoding="utf-8")。


三、高阶模块接口

  • io.DEFAULT_BUFFER_SIZE

包含模块缓冲 I/O 类使用的默认缓冲区大小的 int。
在可能的情况下 open() 将使用文件的 blksize(由 os.stat() 获得)。


  • io.open

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

这是内置的 open() 函数的别名。
open 附带参数 pathmodeflags 会引发 审计事件


  • io.open_code

io.open_code(path)

rb 模式打开提供的文件。
如果目的是将文件内容做为可执行代码,则应使用此函数。

path 应当为 str 类型并且是一个绝对路径。

此函数的行为可以由对 PyFile_SetOpenCodeHook() 的先期调用所重载。但是,如果 pathstr 类型并且是一个绝对路径,open_code(path) 的行为应当总是与 open(path, 'rb') 一致。

重载此行为的目的是为了给文件附加额外的验证或预处理。3.8 新版功能.


  • io.text_encoding(encoding, stacklevel=2)

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

此函数会返回 encoding,如果它不为 None 的话,或是 "locale" ,如果 encodingNone 的话。

如果 sys.flags.warn_default_encoding 为真值并且 encoding 为 None 则此函数会发出 EncodingWarning
stacklevel 指定在哪里发出警告。 例如:

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


  • exception io.BlockingIOError

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


  • exception io.UnsupportedOperation

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

参见: sys: http://study.yali.edu.cn/pythonhelp/library/sys.html#module-sys

包含标准IO流:


四、类的层次结构

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


IOBase

  • RawIOBase
    • FileIO
    • BufferedIOBase
      • BufferedWriter
      • BufferedReader
      • BufferedRWPair
      • BytesIO
  • TextIOBase
    • TextIOWrapper
    • StringIO

注解

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

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

  • 抽象基类 RawIOBaseIOBase 的子类。它负责将字节读取和写入流中。
    RawIOBase 的子类 FileIO 提供计算机文件系统中文件的接口。

  • 抽象基类 BufferedIOBase继承了 IOBase ,处理原始二进制流( RawIOBase )上的缓冲。
    其子类 BufferedWriterBufferedReaderBufferedRWPair 分别缓冲可读、可写以及可读写的原始二进制流。
    BufferedRandom 提供了带缓冲的可随机访问流接口。
    BufferedIOBase 的另一个子类 BytesIO 是内存中字节流。

  • 抽象基类 TextIOBase 继承了 IOBase 。它处理可表示文本的流,并处理字符串的编码和解码。

  • TextIOWrapper 继承了 TextIOBase ,是原始缓冲流( BufferedIOBase)的缓冲文本接口。

  • 最后, StringIO 是文本的内存流。

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


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

抽象基类继承抽象方法Mixin方法和属性
IOBasefileno, seek, 和 truncateclose, closed, __enter__, __exit__, flush, isatty, __iter__, __next__, readable, readline, readlines, seekable, tell, writablewritelines
RawIOBaseIOBasereadintowrite继承 IOBase 方法, read, 和 readall
BufferedIOBaseIOBasedetach, read, read1, 和 write继承 IOBase 方法, readinto, 和 readinto1
TextIOBaseIOBasedetach, read, readline, 和 write继承 IOBase 方法, encoding, errors, 和 newlines

1、I/O 基类

class io.IOBase

The abstract base class for all I/O classes.

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

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

从文件读取或写入文件的二进制数据的基本类型为 bytes 。其他 bytes-like objects 也可以作为方法参数。文本I/O类使用 str 数据。

请注意,在关闭的流上调用任何方法(甚至查询)都是未定义的(undefined)。在这种情况下,实现可能会引发 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
对于文本文件,可以用将 newline 参数传给 open() 的方式来选择要识别的行结束符。


  • readlines(hint=-1)

从流中读取并返回包含多行的列表。
可以指定 hint 来控制要读取的行数:如果(以字节/字符数表示的)所有行的总大小超出了 hint 则将不会读取更多的行。
0 或更小的 hint 值以及 None,会被视为没有 hint。
请注意使用 for line in file: ... 就足够对文件对象进行迭代了,可以不必调用 file.readlines()


  • seek(offset, whence=SEEK_SET)

将流位置修改到给定的字节 offset
offset 将相对于由 whence 指定的位置进行解析。
whence 的默认值为 SEEK_SET,可用值有:SEEK_SET0 – 流的开头(默认值);
offset 应为零或正值SEEK_CUR or 1 – 当前流位置;
offset 可以为负值SEEK_END or 2 – 流的末尾;
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

Base class for raw binary streams. It inherits IOBase.

原始二进制流通常会提供对下层 OS 设备或 API 的低层级访问,而不是尝试将其封装到高层级的基元中(此功能是在更高层级的缓冲二进制流和文本流中实现的,将在下文中描述)。

RawIOBaseIOBase 的现有成员以外还提供了下列方法:


  • read(size=-1)

从对象中读取 size 个字节并将其返回。
作为一个便捷选项,如果 size 未指定或为 -1,则返回所有字节直到 EOF。
在其他情况下,仅会执行一次系统调用。
如果操作系统调用返回字节数少于 size 则此方法也可能返回少于 size 个字节。如果返回 0 个字节而 size 不为零 0,这表明到达文件末尾。 如果处于非阻塞模式并且没有更多字节可用,则返回 None。默认实现会转至 readall()readinto()


  • readall()

从流中读取并返回所有字节直到 EOF,如有必要将对流执行多次调用。


  • readinto(b)

将字节数据读入预先分配的可写 bytes-like object b,并返回所读取的字节数。
例如,b 可以是一个 bytearray
如果对象处理非阻塞模式并且没有更多字节可用,则返回 None


  • write(b)

将给定的 bytes-like object b 写入到下层的原始流,并返回所写入的字节数。
这可以少于 b 的总字节数,具体取决于下层原始流的设定,特别是如果它处于非阻塞模式的话。
如果原始流设为非阻塞并且不能真正向其写入单个字节时则返回 None
调用者可以在此方法返回后释放或改变 b,因此该实现应该仅在方法调用期间访问 b


class io.BufferedIOBase

Base class for binary streams that support some kind of buffering. It inherits IOBase.

RawIOBase 的主要差别在于 read(), readinto()write() 等方法将(分别)尝试按照要求读取尽可能多的输入或是耗尽所有给定的输出,其代价是可能会执行一次以上的系统调用。

除此之外,那些方法还可能引发 BlockingIOError,如果下层的原始数据流处于非阻塞模式并且无法接受或给出足够数据的话;不同于对应的 RawIOBase 方法,它们将永远不会返回 None

并且,read() 方法也没有转向 readinto() 的默认实现。

典型的 BufferedIOBase实现不应当继承自 RawIOBase 实现,而要包装一个该实现,正如 BufferedWriterBufferedReader 所做的那样。

BufferedIOBaseIOBase 的现有成员以外还提供或重载了下列数据属性和方法:


  • raw

BufferedIOBase处理的下层原始流 (RawIOBase 的实例)。 它不是 BufferedIOBase API 的组成部分并且不存在于某些实现中。


  • detach()

从缓冲区分离出下层原始流并将其返回。在原始流被分离之后,缓冲区将处于不可用的状态。
某些缓冲区例如 BytesIO 并无可从此方法返回的单独原始流的概念。
它们将会引发 UnsupportedOperation


  • read(size=-1)

读取并返回最多 size 个字节。 如果此参数被省略、为 None 或为负值,则读取并返回所有数据直到 EOF。
如果流已经到达 EOF 则返回一个空的 bytes 对象。
如果此参数为正值,并且下层原始流不可交互,则可能发起多个原始读取以满足字节计数(直至先遇到 EOF)。
但对于可交互原始流,则将至多发起一个原始读取,并且简短的结果并不意味着已到达 EOF。
BlockingIOError 会在下层原始流不处于阻塞模式,并且当前没有可用数据时被引发。


  • read1([size])

通过至多一次对下层流的 read() (或 readinto()) 方法的调用读取并返回至多 size 个字节。
这适用于在 BufferedIOBase对象之上实现你自己的缓冲区的情况。
如果 size-1 (默认值),则返回任意数量的字节(多于零字节,除非已到达 EOF)。


  • readinto(b)

将字节数据读入预先分配的可写 bytes-like object b 并返回所读取的字节数。
例如,b 可以是一个 bytearray。类似于 read(),可能对下层原始流发起多次读取,除非后者为交互式。
BlockingIOError 会在下层原始流不处于阻塞模式,并且当前没有可用数据时被引发。


  • readinto1(b)

将字节数据读入预先分配的可写 bytes-like object b,其中至多使用一次对下层原始流 read() (或 readinto()) 方法的调用。
返回所读取的字节数。
BlockingIOError 会在下层原始流不处于阻塞模式,并且当前没有可用数据时被引发。3.5 新版功能.


  • write(b)

写入给定的 bytes-like object b,并返回写入的字节数 (总是等于 b 的字节长度,因为如果写入失败则会引发 OSError)。
根据具体实现的不同,这些字节可能被实际写入下层流,或是出于运行效率和冗余等考虑而暂存于缓冲区。
当处于非阻塞模式时,如果需要将数据写入原始流但它无法在不阻塞的情况下接受所有数据则将引发 BlockingIOError
调用者可能会在此方法返回后释放或改变 b,因此该实现应当仅在方法调用期间访问 b


2、原始文件 I/O


class io.FileIO

io.FileIO(name, mode=‘r’, closefd=True, opener=None)

代表一个包含字节数据的 OS 层级文件的原始二进制流。 它继承自 RawIOBase

name 可以是以下两项之一:


  • 代表将被打开的文件路径的字符串或 bytes 对象。 在此情况下 closefd 必须为 True (默认值) 否则将会引发异常。
  • 代表一个现有 OS 层级文件描述符的号码的整数,作为结果的 FileIO 对象将可访问该文件。 当 FileIO 对象被关闭时此 fd 也将被关闭,除非 closefd 设为 False

mode 可以为 r, w, xa 分别表示读取(默认模式)、写入、独占新建或添加。 如果以写入或添加模式打开的文件不存在将自动新建;当以写入模式打开时文件将先清空。 以新建模式打开时如果文件已存在则将引发 FileExistsError
以新建模式打开文件也意味着要写入,因此该模式的行为与 w 类似。 在模式中附带 + 将允许同时读取和写入。

该类的 read() (当附带正值参数调用时), readinto()write() 方法将只执行一次系统调用。

可以通过传入一个可调用对象作为 opener 来使用自定义文件打开器。 然后通过调用 opener 并传入 (name, flags) 来获取文件对象所对应的下层文件描述符。 opener 必须返回一个打开文件描述符(传入 os.open 作为 opener 的结果在功能上将与传入 None 类似)。

新创建的文件是 不可继承的

有关 opener 参数的示例,请参见内置函数 open()

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

在 3.4 版更改: 文件现在禁止继承。

FileIO 在继承自 RawIOBaseIOBase 的现有成员以外还提供了以下数据属性和方法:


  • mode

构造函数中给定的模式。


  • name

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


3、缓冲流

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


class io.BytesIO

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 对象就无法被改变大小或关闭。


  • getvalue()

返回包含整个缓冲区内容的 bytes


  • read1([size])

BytesIO 中,这与 read() 相同。在 3.7 版更改: size 参数现在是可选的。


  • readinto1(b)

BytesIO 中,这与 readinto() 相同。3.5 新版功能.


class io.BufferedReader

io.BufferedReader(raw, buffer_size=DEFAULT_BUFFER_SIZE)

一个提供对可读、不可查找的 RawIOBase 原始二进制流的高层级访问的缓冲二进制流。 它继承自 [BufferedIOBase BufferedIOBase)。

当从此对象读取数据时,可能会从下层原始流请求更大量的数据,并存放到内部缓冲区中。 接下来可以在后续读取时直接返回缓冲数据。

根据给定的可读 raw 流和 buffer_size 创建 BufferedReader 的构造器。 如果省略 buffer_size,则会使用 [DEFAULT_BUFFER_SIZE DEFAULT_BUFFER_SIZE)。

BufferedReader 在继承自 BufferedIOBaseIOBase 的成员以外还提供或重载了下列方法:


  • peek([size])

从流返回字节数据而不前移位置。 完成此调用将至多读取一次原始流。 返回的字节数量可能少于或多于请求的数量。


  • read([size])

读取并返回 size 个字节,如果 size 未给定或为负值,则读取至 EOF 或是在非阻塞模式下读取调用将会阻塞。


  • read1([size])

在原始流上通过单次调用读取并返回至多 size 个字节。 如果至少缓冲了一个字节,则只返回缓冲的字节。 在其他情况下,将执行一次原始流读取。在 3.7 版更改: size 参数现在是可选的。


class io.BufferedWriter

io.BufferedWriter(raw, buffer_size=DEFAULT_BUFFER_SIZE)
一个提供对可写、不可查找的 RawIOBase 原始二进制流的高层级访问的缓冲二进制流。 它继承自 [BufferedIOBase BufferedIOBase)。

当写入到此对象时,数据通常会被放入到内部缓冲区中。 缓冲区将在满足某些条件的情况下被写到下层的 RawIOBase 对象,包括:


  • 当缓冲区对于所有挂起数据而言太小时;
  • 当 [flush() BufferedWriter.flush) 被调用时
  • 当(为 BufferedRandom 对象)请求 seek() 时;
  • BufferedWriter 对象被关闭或销毁时。

该构造器会为给定的可写 raw 流创建一个 BufferedWriter。 如果未给定 buffer_size,则使用默认的 [DEFAULT_BUFFER_SIZE DEFAULT_BUFFER_SIZE)。

BufferedWriter 在继承自 BufferedIOBaseIOBase 的成员以外还提供或重载了下列方法:


  • flush()

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


  • write(b)

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


class io.BufferedRandom

io.BufferedRandom(raw, buffer_size=DEFAULT_BUFFER_SIZE)

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

该构造器会为在第一个参数中给定的可查找原始流创建一个读取器和写入器。 如果省略 buffer_size 则使用默认的 [DEFAULT_BUFFER_SIZE DEFAULT_BUFFER_SIZE)。

BufferedRandom 能做到 BufferedReaderBufferedWriter 所能做的任何事。 此外,还会确保实现 seek()tell()


class io.BufferedRWPair

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

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

readerwriter 分别是可读和可写的 RawIOBase 对象。 如果省略 buffer_size 则使用默认的 [DEFAULT_BUFFER_SIZE DEFAULT_BUFFER_SIZE)。

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

警告 : BufferedRWPair 不会尝试同步访问其下层的原始流。 你不应当将传给它与读取器和写入器相同的对象;而要改用 BufferedRandom


4、文本 I/O


class io.TextIOBase

Base class for text streams. This class provides a character and line based interface to stream I/O. It inherits IOBase.

TextIOBase 在来自 IOBase 的成员以外还提供或重载了以下数据属性和方法:


  • encoding

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


  • errors

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


  • newlines

一个字符串、字符串元组或者 None,表示目前已经转写的新行。 根据具体实现和初始构造器旗标的不同,此属性或许会不可用。


  • buffer

TextIOBase 处理的下层二进制缓冲区(为一个 BufferedIOBase的实例)。 它不是 TextIOBaseAPI 的组成部分并且不存在于某些实现中。


  • 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_SETSEEK_SET0: 从流的开始位置起查找(默认值);offset 必须为 [TextIOBase.tell() TextIOBase.tell) 所返回的数值或为零。 任何其他 offset 值都将导致未定义的行为。SEEK_CUR1: “查找” 到当前位置;offset 必须为零,表示无操作(所有其他值均不受支持)。SEEK_END2: 查找到流的末尾;offset 必须为零(所有其他值均不受支持)。以不透明数字形式返回新的绝对位置。3.1 新版功能: SEEK_* 常量.


  • tell()

以不透明数字形式返回当前流的位置。 该数字通常并不代表下层二进制存储中对应的字节数。


  • write(s)

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


class io.TextIOWrapper

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

一个提供对 BufferedIOBase缓冲二进制流的高层级访问的缓冲文本流。 它继承自 TextIOBase

encoding 给出流的解码和编码将会使用的编码格式的名称。 它默认为 locale.getpreferredencoding(False)encoding="locale" 可被用来地指定当前语言区域的编码格式。 请参阅 文本编码格式 了解更多信息。

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。 如果 newline 为 ``,也会启用通用换行模式,但行结束符会不加转写即返回给调用者。 如果 newline 具有任何其他合法的值,则输入行将仅由给定的字符串结束,并且行结束符会不加转写即返回给调用者。
  • 将输出写入流时,如果 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() 来临时改变区域编码格式,要使用当前区域编码格式而不是用户的首选编码格式。

在 3.10 版更改: encoding 参数现在支持 "locale" 作为编码格式名称。

TextIOWrapper 在继承自 TextIOBaseIOBase 的现有成员以外还提供了以下数据属性和方法:


  • line_buffering

是否启用行缓冲。


  • write_through

写入是否要立即传给下层的二进制缓冲。3.7 新版功能.


  • reconfigure([, encoding][, errors][, newline][, line_buffering][, write_through])

使用 encoding, errors, newline, line_bufferingwrite_through 的新设置来重新配置此文本流。

未指定的形参将保留当前设定,例外情况是当指定了 encoding 但未指定 errors 时将会使用 errors='strict'

如果已经有数据从流中被读取则将无法再改变编码格式或行结束符。
另一方面,在写入数据之后再改变编码格式则是可以的。

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


class io.StringIO

`io.StringIO(initial_value=‘’, newline=‘\n’)

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

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

缓冲区的初始值可通过提供 initial_value 来设置。
如果启用了行结束符转写,换行将以 write() 所用的方式被编码。
数据流位置将被设为缓冲区的开头。

newline 参数的规则与 TextIOWrapper 所用的一致,不同之处在于当将输出写入到流时,如果 newlineNone,则在所有平台上换行符都会被写入为 \n

StringIO 在继承自 TextIOBaseIOBase 的现有成员以外还提供了以下方法:


  • getvalue()

返回一个包含缓冲区全部内容的 str。 换行符会以与 [read() TextIOBase.read) 相同的方式被编码,但是流的位置不会被改变。


用法示例:

import io

f = io.StringIO("123abc") 
print(f) # <_io.StringIO object at 0x7f8efa328cd0>
print(f.getvalue()) # 123abc
f.close()

f = io.StringIO()
f.write('abc123')
print(f.getvalue()) # abc123 
f.close()


class io.IncrementalNewlineDecoder

用于在 universal newlines 模式下解码换行符的辅助编解码器。
它继承自 codecs.IncrementalDecoder


五、性能

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


1、二进制 I/O

即使在用户请求单个字节时,也只读取和写入大块数据。
通过该方法,缓冲 I/O 隐藏了操作系统调用和执行无缓冲 I/O 例程时的任何低效性。增益取决于操作系统和执行的 I/O 类型。
例如,在某些现代操作系统上(例如 Linux),无缓冲磁盘 I/O 可以与缓冲 I/O 一样快。
但最重要的是,无论平台和支持设备如何,缓冲 I/O 都能提供可预测的性能。
因此,对于二进制数据,应首选使用缓冲的 I/O 而不是未缓冲的 I/O 。


2、文本 I/O

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

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


3、多线程

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

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

TextIOWrapper 对象不再是线程安全的。


4、可重入性

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

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


使用示例

StringIO 的使用

cache_file = StringIO()
print(cache_file.write('hello world!')) # 12, 字符长度
print(cache_file.seek(0)) # 0
print(cache_file.read()) # hello world!
print(cache_file.close())  # 释放缓冲区
  • StringIO 经常被用来作字符串的缓存,因为StringIO的一些接口和文件操作是一致的,也就是说同样的代码,可以同时当成文件操作或者StringIO操作;
  • 要读取StringIO,可以用一个str初始化StringIO,然后像读文件一样读取;
  • 当使用read()方法读取写入的内容时,则需要先用seek()方法让指针移动到最开始的位置,否则读取不到内容(写入后指针在最末尾);
  • getvalue()方法:直接获得写入后的str;
  • close()方法:在关闭文件的缓冲区之后就不能再进行读写操作了;

bytes_file = BytesIO()
bytes_file.write(b'hello world')
bytes_file.seek(3)
print(bytes_file.read()) # b'lo world'
bytes_file.close()
  • StringIO 操作的只能是 str,如果要操作二进制数据,就需要使用 BytesIO;
  • BytesIO 实现了在内存中读写bytes,写入的不是str,而是经过 UTF-8 编码的 bytes;
  • 要读取 BytesIO,可以用一个 bytes 初始化 BytesIO,然后像读文件一样读取;

2022-05-25

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值