# 16.2. `io` - 使用流的核心工具

源代码： Lib/io.py

## 16.2.1. 概览

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

独立于其类别，每个具体的流对象也将具有各种能力：它可以是只读的，只写的或读写的。它还可以允许任意随机存取（寻找向前或向后到任何位置），或只允许顺序存取（例如在套接字或管道的情况下）。

所有流都仔细考虑您给他们的数据类型。例如，给二进制流的`str`对象`write()`方法将报`TypeError`错。因此，将向文本流的`write()`方法提供`bytes`对象。

在版本3.3中已更改：由于`IOError`现在是一个别名，因此用于引发`IOError`的操作现已引发`OSError` `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）期望字节状对象并产生`字节`对象。不执行编码，解码或换行。这种类别的流可以用于所有种类的非文本数据，并且当需要对文本数据的处理的手动控制时。

创建二进制流的最简单方法是在模式字符串中使用`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（也称为无缓冲I / O）通常用作二进制和文本流的低级构建块；它很少用于直接操作来自用户代码的原始流。不过，您可以通过在禁用缓冲的情况下以二进制模式打开文件来创建原始流：

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

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

## 16.2.2. 高级模块接口

`io.``DEFAULT_BUFFER_SIZE`

  包含由模块的缓冲I / O类使用的默认缓冲区大小的int。`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`

  在流上调用不受支持的操作时引发的异常,继承了`OSError`和`ValueError`。

### 16.2.2.1. 内存中的流

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

也可以看看

`sys`
  包含标准IO流：`sys.stdin`，`sys.stdout`和`sys.stderr`。

## 16.2.3. 类的层次

I / O流的实现被组织为类的层次结构。第一个抽象基础类/abstract base classes（ABCs），用于指定流的各种类别，然后是提供标准流实现的具体类。

> 注意

> 抽象基础类也提供某些方法的默认实现为了有助于实现具体流类. 例如, `BufferedIOBase`提供非优化的实现`readinto()` 和`readline()`.

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

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

`BufferedIOBase` ABC处理原始字节流（`RawIOBase`）上的缓冲。其子类，可读，可写，可读可写的`BufferedWriter`，`BufferedReader`和`BufferedRWPair` `BufferedRandom`为随机存取流提供缓冲接口。另一个`BufferedIOBase`子类，`BytesIO`是一个内存中字节流。

`TextIOBase` ABC是`IOBase`的另一个子类，它处理字节代表文本的流，并处理字符串的编码和解码。`TextIOWrapper`（扩展它）是缓冲的原始流的缓冲文本接口（`BufferedIOBase`）。最后，`StringIO`是文本的内存流。

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

下表总结了由`io`模块提供的ABC：

抽象基类 | 继承 | 存根方法 | Mixin方法和属性
--- | --- | --- | ---
`IOBase` |  | `fileno`，`seek`和`truncate` | `close`, `closed`, `__enter__`, `__exit__`, `flush`, `isatty`, `__iter__`, `__next__`, `readable`, `readline`, `readlines`, `seekable`, `tell`, `writable`, and `writelines`
`RawIOBase` | `IOBase` | `readinto`和`write` | 继承`IOBase`方法，`read`和`readall`
`BufferedIOBase` | `IOBase` | `detach`，`read`，`read1`和`write` | 继承`IOBase`方法，`readinto`
`TextIOBase` | `IOBase` | `detach`，`read`，`readline`和`write` | 继承了`IOBase`方法，`encoding`，`errors`和`newlines`

### 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`语句。在此示例中，文件在`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()`的换行符参数可用于选择识别的行终止符。

  `readlines`(hint=-1)

    读取并返回流中的行列表。可以指定提示以控制读取的行数：如果所有行的总大小（以字节/字符）超过hint，则不会再读取行。

    请注意，已经可以在 文件中使用`来为 行 迭代文件对象：` ...，而无需调用`file.readlines()`。

  `seek`(offset[, whence])

    将流位置更改为给定字节偏移量。偏移相对于由whence指示的位置进行解释。whence的默认值为`SEEK_SET`。whence的值为：

    - `SEEK_SET`或`0` - 流的开始（默认）； offset应为零或正数
    - `SEEK_CUR`或`1` - 当前流位置； offset可能为负值
    - `SEEK_END`或`2` - 流的结束； offset通常为负数

    返回新的绝对位置。

    版本3.1中的新功能： `SEEK_*`常数。

    版本3.3中的新功能：某些操作系统可能支持其他值，例如`os.SEEK_HOLE`或`os.SEEK_DATA`。文件的有效值可能取决于它是以文本还是二进制模式打开。

  `seekable`()

    如果流支持随机访问，则返回`True`。If `False`, `seek()`, `tell()` and `truncate()` will raise `OSError`.

  `tell`()

    返回当前流位置。

  `truncate`(size=None)

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

  在3.5版本中已更改： Windows将在扩展时将零填充文件。

  `writable`()

    如果流支持写入，则返回`True`。如果`False`，`write()`和`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()`。否则，只有一个系统调用。如果操作系统调用返回的小于大小字节，则可能会返回小于大小的字节。

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

  `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`实现，而是像第一个`BufferedWriter`和`BufferedReader`

  `BufferedIOBase`除了来自`IOBase`的方法和属性，还提供或覆盖这些方法和属性：

  `raw`

    `BufferedIOBase`处理的基本原始流（`RawIOBase`实例）。这不是`BufferedIOBase` API的一部分，在某些实现上可能不存在。

  `detach`()

    从缓冲区分离下层原始流并返回它。

    在原始流已经分离之后，缓冲器处于不可用状态。

    一些缓冲区，如`BytesIO`，没有从此方法返回的单个原始流的概念。他们引发`UnsupportedOperation`。

    版本3.1中的新功能。

  `read`(size=-1)

    读取并返回大小大小字节。如果省略参数，则`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()`()函数将字节读入预分配的可写bytes-like object b或`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`接口）。

  名称可以是以下两种情况之一：

  - 一个字符串或`bytes`对象，表示要打开的文件的路径。在这种情况下，closefd必须为True（默认值），否则会引发错误。
  - 一个表示现有OS级别文件的编号的整数，由此产生的`FileIO`对象将赋予访问权限。当FileIO对象关闭时，fd也将关闭，除非closefd设置为`False`。

  模式可以是`'r'`，`'w'`，`'x'`或`'a'`用于阅读（默认），书写，独家创作或追加。该文件将被创建，如果它不存在时打开进行写或附加；它会在打开时被截断。`FileExistsError`将会被提出，如果它在打开时已经存在。打开用于创建的文件意味着写入，因此此模式的行为方式类似于`'w'`。将`'+'`添加到模式以允许同时读取和写入。

  `read()`（当使用正参数调用时），此类的`readinto()`和`write()`

  通过传递可调用对象opener可以使用自定义开启器。然后通过使用（名称，标志）调用opener获得文件对象的基础文件描述器。opener必须返回一个打开的文件描述器（传递`os.open`为opener 结果类似的功能 `None`）。

  新创建的文件为non-inheritable。

  有关使用开启参数的示例，请参见`open()`内建函数。

  在版本3.3中已更改：添加了开启程序参数。添加了`'x'`模式。

  在版本3.4中更改：此文件现在是不可继承的。

  除了`IOBase`和`RawIOBase`的属性和方法，`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。

  除了来自`BufferedIOBase`和`IOBase`的`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`。

  `BufferedReader`除了来自`BufferedIOBase`和`IOBase`的方法，还提供或覆盖这些方法：

  `peek`([size])

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

  `read`([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`除了提供或覆盖来自`BufferedIOBase`和`IOBase`的方法：

  `flush`()

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

  `write`(b)

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

class `io.``BufferedRandom`(raw, buffer_size=DEFAULT_BUFFER_SIZE)

  缓冲接口，用于随机访问流。它继承`BufferedReader`和`BufferedWriter`，并进一步支持`seek()`和`tell()`功能。

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

  `BufferedRandom`能够处理任何`BufferedReader`或`BufferedWriter`。

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

  缓冲I / O对象将两个单向`RawIOBase`对象（一个可读，另一个可写）组合到单个双向端点中。它继承`BufferedIOBase`。

  读取器和写入器是分别可读和可写的`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`。这里没有公共构造函数。

  `TextIOBase` 提供或重写这些数据的属性和方法除了那些从 `IOBase`:

  `encoding`

    用来解码流的字节转换为字符串，并将字符串编码为字节编码的名称。

  `errors`

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

  `newlines`

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

  `buffer`

    `TextIOBase`处理的基本二进制缓冲区（`BufferedIOBase`实例）。这不是`TextIOBase` API的一部分，在某些实现中可能不存在。

  `detach`()

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

    分离下层缓冲区后，`TextIOBase`处于不可用状态。

    一些`TextIOBase`实现，如`StringIO`，可能没有底层缓冲区的概念，并调用此方法将引发`UnsupportedOperation`。

    版本3.1中的新功能。

  `read`(size)

    从流中读取并最多返回大小字符，作为单个`str`。如果size为负数或`None`，则一直读取到EOF。

  `readline`(size=-1)

    一直读取到换行符或EOF并返回单个`str`。如果流已经到EOF，则返回一个空字符串。

    如果指定size，则最多只能读取size个字符。

  `seek`(offset[, whence])

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

    - `SEEK_SET`或`0`：从流的开始寻找（默认）； offset必须是由`TextIOBase.tell()`返回的数字，或零。任何其他偏移值会产生未定义的行为。
    - `SEEK_CUR`或`1`：“seek”到当前位置； offset必须为零，这是一个无操作（所有其他值都不受支持）。
    - `SEEK_END`或`2`：寻找流的结尾； 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是一个可选字符串，用于指定如何处理编码和解码错误。Pass `'strict'` to raise a `ValueError` exception if there is an encoding error (the default of `None` has the same effect), or pass `'ignore'` to ignore errors. （请注意，忽略编码错误可能会导致数据丢失。）`'replace'`会导致替换标记（例如`'?'`）插入到存在格式错误的数据的位置。`'backslashreplace'`导致格式错误的数据被反斜杠转义序列替换。写入时，`'xmlcharrefreplace'`（替换为相应的XML字符引用）或`'namereplace'`（替换为`\N{...}`已使用`codecs.register_error()`注册的任何其他错误处理名称也有效。

  换行符控制如何处理行尾。它可以是`None`、`''`、`'\n'`、`'\r'`、`'\r\n'`。它的工作原理如下：

  - 从流读取输入时，如果换行符为`None`，则启用universal newlines模式。输入中的行可以以`'\n'`，`'\r'`或`'\r\n'`结尾，在`'\n'`中，然后返回给调用者。如果它是`''`，则启用通用换行符模式，但行结尾将返回给未转换的调用者。如果它具有任何其他合法值，则输入行仅由给定字符串终止，并且行结尾被返回给未经翻译的调用者。
  - 将输出写入流时，如果newline为`None`，则写入的任何`'\n'`字符都将转换为系统默认行分隔符`os.linesep`。如果换行符是`''`或`'\n'`，则不会进行转换。如果换行符是任何其他合法值，写入的任何`'\n'`字符都将转换为给定字符串。

  如果line_buffering是`True`，则当写入调用包含换行符时，将隐含`flush()`。

  If write_through is `True`, calls to `write()` are guaranteed not to be buffered: any data written on the `TextIOWrapper` object is immediately handled to its underlying binary buffer.

  在版本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()`进行编码。流位于缓冲区的开始。

  换行符参数的工作方式类似于`TextIOWrapper`。默认设置仅将`\n`字符视为行的末尾，并且不进行换行。如果换行符设置为`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)`）范围内是线程安全的，它们也是线程安全的。

二进制缓冲对象（`BufferedReader`，`BufferedWriter`，`BufferedRandom`和`BufferedRWPair`）的实例使用锁保护其内部结构；因此可以安全地同时从多个线程调用它们。

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

### 16.2.4.4. 重入

二进制缓冲对象（`BufferedReader`，`BufferedWriter`，`BufferedRandom`和`BufferedRWPair`）的实例不可重入。虽然在正常情况下不会发生可重入呼叫，但它们可能来自在`signal`处理程序中执行I / O。如果线程尝试重新输入它已经访问的缓冲对象，则会引发`RuntimeError`。注意，这并不禁止不同的线程进入缓冲对象。

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