open模块
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
-
打开给定路径的
file
文件, 并返回对应的一个file object
; -
如果要打开的文件,不能被打开,就会触发
OSError
异常; -
file
是一个路径对象(str),表示将要打开的文件路径(绝对路径或当前工作目录的相对路径),也可以是被封装的整数类型文件描述符;- 如果是文件描述符,它会随着返回的
I/O
对象关闭而关闭,除非closefd
被设为False;
- 如果是文件描述符,它会随着返回的
-
mode
是一个可选字符串,用于指定打开文件的模式。默认是r
,也就是默认以文本模式打开并读取。-
字符 含义 ‘r’ 读取(默认) ‘w’ 写入,并先截断文件原本内容 ‘x’ 排它性创建,如果文件已存在则失败 ‘b’ 二进制模式 ‘a’ 写入,如果文件存在则在末尾追加 ‘t’ 文本模式(默认) ‘+’ 打开用于更新(读取与写入) -
默认模式为
'r'
(打开用于读取文本,与rt
同义)。 -
模式
'w+'
与'w+b'
将打开文件并清空内容。 -
模式
'r+'
与'r+b'
将打开文件并不清空内容。
-
-
在文本模式,如果
encoding
没有指定,则根据系统平台来决定使用的编码。可以使用locale.getpreferredenconding(False)
来获取自己平台的编码。>>> import locale >>> locale.getpreferredencoding(False) 'cp936' # 我的系统编码
-
buffering
是一个可选的整数,用于设置缓冲策略。-
传递0以切换缓冲关闭(仅支持二进制模式下)
>>> import os >>> os.getcwd() # 查看当前工作目录 'C:\\Users\\www13\\AppData\\Local\\Programs\\Python\\Python38-32' >>> ab = open('d:/data.txt', 'ab', buffering=0) # 创建一个没有缓冲区的 file object >>> ab.write('hello 你好啊') # 写入正常字符串,报错 --------------------------Error------------------------------- Traceback (most recent call last): File "<pyshell#4>", line 1, in <module> ab.write('hello 你好啊') TypeError: a bytes-like object is required, not 'str' ---------------------------错误-------------------------------- >>> ab.write(bytes('hello 你好啊'.encode())) # 写入二进制字符串,响应正常为写入字节长度并且不需要close或flush就可以在文本中看到。 15
-
传递1选择行缓冲(仅支持文本模式下可用),并且
>1
的整数以指定固定大小的块缓冲区的大小(以字节为单位)。>>> ab = open('d:/data.txt', 'at', buffering=1) # 创建行缓冲 file object >>> ab.write('你好,Vin\n') # \n换行符结尾,自动刷新缓冲区 7 >>> ab.write('你好,Vin') # 不会刷新缓冲区 6 >>> ab.write('你好,蟒蛇\n') # 自动刷新缓冲区 6 >>> ab.write('你好,蟒蛇2') 6 >>> ab.write('你好,蟒蛇3') 6 >>> ab.write('你好蟒蛇4\n') 6 >>> # 也就是说,buffering参数设置为1的情况下,想让它刷新缓冲区,它只认得 \n 这个东西。 >>> ab = open('d:/data.txt', 'ab', buffering=5) # 创建自定义字节大小缓冲 file object >>> ab.write(bytes('hello'.encode())) # 刚好五个字节,不会刷新缓冲区。 5 >>> ab.flush() # 先把之前的缓冲区刷新一下 >>> ab.write(bytes('buffering=5'.encode())) # 大于五个字节,自动刷新缓冲区。 11
-
如果没有给
buffering
参数,则默认缓冲策略的工作方式如下:- 二进制文件以固定大小的块进行缓冲;使用启发式方法选择缓冲区的大小,尝试确定底层设备的“块大小”或使用
io.DEFAULT_BUFFER_SIZE
。在许多系统上,缓冲区的长度通常为4096或8192字节。 - “交互式”文本文件(
isatty()
返回True
的文件)使用行缓冲。其它文本文件使用上述策略用于二进制文件。
>>> ab = open('d:/data.txt', 'ab') # 创建一个有缓冲区的 file object >>> ab.write(bytes('hi LiLa Vin'.encode())) # 写入响应正常,但是文本却看不到,因为还在缓冲区中,没有到达默认的缓冲区长度。 11 >>> ab.close() # 或 ab.flush
- 二进制文件以固定大小的块进行缓冲;使用启发式方法选择缓冲区的大小,尝试确定底层设备的“块大小”或使用
-
-
encoding
是用于解码或编码文件的编码名称。- 这
应该
只在文本模式下使用(也就是官方不建议使用二进制模式下,给encoding
传值) - 默认编码是依赖于平台的(不管
locale.getpreferredencoding()
返回任何值),但可以使用任何Python支持的文本编码方式
。
- 这
-
errors
是一个可选的字符串参数- 用于指定如何处理编码和解码错误(这不能在二进制模式下使用)。
- 可以使用各种标准错误处理程序,但是使用
codecs.register_error()
注册的任何错误处理名称也是有效的。标准名称包括:- 如果存在编码错误,
'strict'
会引发ValueError
异常。默认值None
具有相同的效果。 'ignore'
忽略错误。如果忽略错误可能会导致数据丢失。'replace'
会将替换标记(例如'?'
)插入有错误数据的地方。'surrogateescape'
将表示任何不正确的字节作为Unicode专用区中的代码点,范围从U+DC80到U+DCFF。当在写入数据时使用surrogateescape
错误处理程序时,这些私有代码点将被转回到相同的字节中。这对于处理未知编码的文件很有用。'xmlcharrefreplace'
只支持写入文件的时候使用。编码不支持的字符串将替换为相应的XML字符串引用,如:&#nnn;
;'backslashreplace'
用Python的反向转义序列替换格式错误的数据。'namereplace'
同样也只支持写入的时候使用,用\N{...}
转义序列替换不支持的字符。
- 如果存在编码错误,
-
newline
控制 通用换行(universal newlines
)如何生效(仅支持文本模式)。它可以使None
,''
,'\n'
,'\r'
和'\r\n'
。它的工作原理:- 从流中读取输入时,如果
newline
为None
,则启用通用换行模式。 - 输入中的行可以以
'\n'
,'\r'
或'\r\n'
结尾,这些行被翻译成'\n'
在返回使用者之前。 - 如果它是
''
,则启用通用换行模式,但行结尾将返回给调用者untranslated。 - 如果它是有任何其它合法值,则输入行仅由给定字符串终止,并且行结尾将返回给未调用的调用者。
- 从流中读取输入时,如果
-
closefd
- 如果
closefd
是False
并且给出了文件描述符而不是文件名,那么当文件关闭时,底层文件描述符将保持打开状态 - 如果给出文件名则
closefd
必须为True(默认值),否则将引发报错。
- 如果
-
opener
自定义open
- 可以通过传递可调用的
function
来使用自定义开启器。然后通过使用参数(file, flags)调用opener 获得文件对象的基础文件描述符。 - opener必须返回一个打开的文件描述符(使用
os.open
asopener
时与传递None的效果相同)。 - 新创建的文件是不可继承的。
- Windows不可用的方法
- 可以通过传递可调用的
open()
函数相应类型
-
函数所返回的
file object
类型取决于所用模式。-
当使用
open()
以文本模式('w'
,'r'
,wt
,rt
等)打开文件的时候,它将返回io.TextIOBase
(特别是io.TextIOWrapper
)的一个子类。>>> open('D:/data.txt', 'w') <_io.TextIOWrapper name='D:/data.txt' mode='w' encoding='cp936'>
-
当使用缓冲以二进制模式打开文件的时候,返回的类型是
io.BufferedIOBase
的一个子类。>>> open('D:/data2.txt', 'xb') <_io.BufferedWriter name='D:/data2.txt'>
-
在只读的二进制模式下,它将返回
io.BufferedReader
;>>> open('D:/data.txt', 'rb') <_io.BufferedReader name='D:/data.txt'>
-
在写入二进制和追加二进制模式下,它将返回
io.BufferedWriter
,而在读/写模式下,它将返回io.BufferedRandom
。>>> open('D:/data.txt', 'ab+') <_io.BufferedRandom name='D:/data.txt'>
-
当禁用缓冲时,则会返回原始流,即
io.RawIOBase
的一个子类io.FileIO
。>>> open('D:/data.txt', 'ab+', buffering=0) <_io.FileIO name='D:/data.txt' mode='ab+' closefd=True>
-
操作模式演示
-
'r'
(默认)读取''' 先创建一个文本类型文件(*.txt),写入以下文本: open the file. this is the cecond row. this is the last row. ''' >>> r = open("../data.txt", "r") >>> read = r.read() # 调用读取方法 >>> print(type(read)) # 查看文本类型 >>> print(read) # 查看读取到的内容 <class 'str'> 'open the file.' 'this is the cecond row.' 'this is the last row.'
-
可以看到,给一个
file
文件路径和mode
读取模式可以正常读取到英文文本。 -
读取中文会引发一个异常:``UnicodeDecodeError
,说
’gbk’` 解码器无法UnicodeDecodeError: 'gbk' codec can't decode byte 0xb6 in position 14: illegal multibyte sequence 'gbk'编码器不能解码 0xb6,在第14行。
-
这种问题给
open
方法的第三个参数,也就是encoding
形参赋值,如使用万能码:utf-8
就可以解决!>>> r = open("../data.txt", "r", encoding="utf-8") >>> read = r.read() >>> print(type(read)) >>> print(read) <class 'str'> open the file. this is the cecond row. this is the last row. 你好啊,Python! # 读取到中文,不会引发异常啦。
-
-
'w'
写入并截断文本原来的内容>>> w = open("../data.txt", "w") >>> print(w.write("写入一行新文本!")) # 打印写入字符的长度 >>> w.close() 8
- 将
写入一行新文本!
写入同一个文本中,但是原本的文本内容会先被清空。
- 将
-
'x'
排它性创建文本>>> x = open("../data.txt", "x", encoding="utf-8-sig") # 创建已经存在的文本
-
会抛出异常:
FileExistsError
FileExistsError: [Errno 17] File exists: '../data.txt'
-
-
'b'
二进制模式>>> r = open('../data.txt', 'r') >>> print(r.read()) # 正常读取字符串 b'open the file' # 得到的结果是bytes类型
- 可以读取二进制内容,不可以写入,读取效率高
-
'a'
追加模式>>> a = open('../data.txt', 'r', encoding='utf-8') >>> lens = a.write('\n我来凑第二行!') >>> a.close() >>> print(lens) 8
- 可以看到写入成功,如果打印结果有你写入的字符长度但是文本内没有,重新打开也没有,那肯定是没有
close()
来关闭I/O流
或者使用a.flush()
来刷新I/O流
。 - 如果
a
模式追加的文件没有,则创建新文件,如果有则在文本末尾追加。
- 可以看到写入成功,如果打印结果有你写入的字符长度但是文本内没有,重新打开也没有,那肯定是没有
-
't'
文本模式,只是一个辅助作用,就等于'r'
模式隐式的添加了t了'rt'
,其它模式也是一样,'wt','at'等等
-
'+'
读取和写入,这个'+'
必须要与有读或者写能力的模式,来进行配合使用,等同于给读模式添加了写入功能'r+'
。- 单独的
'b+'
,没有读写功能,要使用'b+w'
或者'b+r'
写入二进制和读取二进制,但是不建议使用读取模式写入,写入模式读取。因为会怪怪的,让人很不适应。
- 单独的
-
'U'
模式已经启用,没有任何功能。之前它会在文本模式中启用通用换行
,也就是universal newlines
。
Python区分二进制和文本I/O
- 以二进制模式打开的文件(包括
mode
参数中的b
)返回的内容为bytes对象,不进行任何解码。 - 在文本模式下(默认情况下,或者在
mode
参数中包含't'
时)文件内容返回为str
,首先使用指定的encoding
(如果给定)或者使用平台默认的字节编码解码。
io.IOBase
所有 I/O类的抽象父类,作用于字节流。没有公共构造函数。
此类为许多方法提供了空的抽象实现,派生类可以选择重写。默认实现代表无法读取、写入或查找的文件。
IOBase
没有声明read() 或 write(),因为它们的签名会有所不同,但是实现和客户端应该将这些方法视为接口的一部分。此外,当调用不支持的操作时可能会引发ValueError
或UnsupportedOperation
。
从文本读取或写入文件的二进制数据的基本类型为bytes
。其它 bytes-like objects
也可以作为方法参数。文本 I/O类使用 str
数据。
在关闭的流商调用任何方法(甚至查询)都是未定义的(undefined)。 在这种情况下,实现可能会引发 ValueError
。
IOBase
(及其子类) 支持迭代器协议,这意味着可以迭代 IOBase
对象以产生流中的行。根据流的二进制流(产生字节)还是文本流(产生字符串),行的定义略有不同。通过 readline()
查看。
IOBase
也是一个上下文管理器,因此支持 with
语句。在这个实例中,file 将在 with 语句块执行完成后被关闭 。即使是发生了异常,也是会关闭。
io
— 处理流的核心工具
源代码: Lib/io.py
概述
io
模块提供了 Python 用于处理各种 I/O 类型的主要工具。三种主要的 I/O类型分别为: 文本 I/O, 二进制 I/O 和 原始 I/O。这些是泛型类型,有很多种后端存储可以用在他们上面。一个隶属于任何这些类型的具体对象被称作 file object。 其他同类的术语还有 流 和 类文件对象。
独立于其类别,每个具体流对象也将具有各种功能:它可以是只读,只写或读写。它还可以允许任意随机访问(向前或向后寻找任何位置),或仅允许顺序访问(例如在套接字或管道的情况下)。
所有流对提供给它们的数据类型都很敏感。例如将 str
对象给二进制流的 write()
方法会引发 TypeError
。将 bytes
对象提供给文本流的 write()
方法也是如此。
在 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")
TextIOBase
的文档中详细描述了文本流的API
二进制 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()
的示例。
原始 I/O
原始 I/O(也称为 非缓冲 I/O)通常用作二进制和文本流的低级构建块。用户代码直接操作原始流的用法非常罕见。不过,可以通过在禁用缓冲的情况下以二进制模式打开文件来创建原始流:
f = open("myfile.jpg", "rb", buffering=0)
RawIOBase
的文档中详细描述了原始流的API
高阶模块接口
-
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) -
io.``open_code
(path)以
'rb'
模式打开提供的文件。如果目的是将文件内容做为可执行代码,则应使用此函数。path
应当为str
类型并且是一个绝对路径。此函数的行为可以由对PyFile_SetOpenCodeHook()
的先期调用所重载。 但是,如果path
为str
类型并且是一个绝对路径,open_code(path)
的行为应当总是与open(path, 'rb')
一致。 重载此行为的目的是为了给文件附加额外的验证或预处理。3.8 新版功能. -
exception
io.``BlockingIOError
这是内置的
BlockingIOError
异常的兼容性别名。 -
exception
io.``UnsupportedOperation
在流上调用不支持的操作时引发的继承
OSError
和ValueError
的异常。
内存中的流
也可以使用 str
或 bytes-like object 作为文件进行读取和写入。对于字符串, StringIO
可以像在文本模式下打开的文件一样使用。 BytesIO
可以像以二进制模式打开的文件一样使用。两者都提供完整的随机读写功能。
参见
-
包含标准IO流:
sys.stdin
,sys.stdout
和sys.stderr
。
类的层次结构
I/O 流被安排为按类的层次结构实现。 首先是 抽象基类 (ABC),用于指定流的各种类别,然后是提供标准流实现的具体类。
注解
抽象基类还提供某些方法的默认实现,以帮助实现具体的流类。例如
BufferedIOBase
提供了readinto()
和readline()
的未优化实现。
I/O层次结构的顶部是抽象基类 IOBase
。它定义了流的基本接口。但是请注意,对流的读取和写入之间没有分离。如果实现不支持指定的操作,则会引发 UnsupportedOperation
。
抽象基类 RawIOBase
是 IOBase
的子类。它负责将字节读取和写入流中。 RawIOBase
的子类 FileIO
提供计算机文件系统中文件的接口。
抽象基类 BufferedIOBase
处理原始字节流( RawIOBase
)上的缓冲。其子类 BufferedWriter
、 BufferedReader
和 BufferedRWPair
缓冲流是可读、可写以及可读写的。 BufferedRandom
为随机访问流提供缓冲接口。 BufferedIOBase
的另一个子类 BytesIO
是内存中字节流。
抽象基类 TextIOBase
是 IOBase
的另一个子类,它处理字节表示文本的流,并处理字符串之间的编码和解码。其一个子类 TextIOWrapper
是原始缓冲流( BufferedIOBase
)的缓冲文本接口。另一个子类 StringIO
用于文本的内存流。
参数名不是规范的一部分,只有 open()
的参数才用作关键字参数。
下表总结了抽象基类提供的 io
模块:
抽象基类 | 继承 | 抽象方法 | Mixin方法和属性 |
---|---|---|---|
IOBase | fileno , seek , 和 truncate | close , closed , __enter__ , __exit__ , flush , isatty , __iter__ , __next__ , readable , readline , readlines , seekable , tell , writable 和 writelines | |
RawIOBase | IOBase | readinto 和 write | 继承 IOBase 方法, read , 和 readall |
BufferedIOBase | IOBase | detach , read , read1 , 和 write | 继承 IOBase 方法, readinto , 和 readinto1 |
TextIOBase | IOBase | detach , read , readline , 和 write | 继承 IOBase 方法, encoding , errors , 和 newlines |
I/O基类
class io.IOBase
所有 I/O 类的抽象基类,作用于字节流。没有公共构造函数。
此类为许多方法提供了空的抽象实现,派生类可以有选择地重写。默认实现代表一个无法读取、写入或查找的文件。
尽管 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
提供以下数据属性和方法:
-
isatty
()- 如果流是交互式的(即连接到终端/tty设备),则返回
True
。
- 如果流是交互式的(即连接到终端/tty设备),则返回
-
fileno
()- 返回文件底层描述符(整数)–如果存在的话。
- 如果IO对象不使用文件描述符,会引发
OSError
。
-
close
()- 刷新并关闭流。
- 如果文件已经关闭,此方法无效。文件关闭后,对文件的任何操作(例如读或写),都会引发
ValueError
。
-
closed
- 如果流已关闭,则返回True。如果流没有关闭则返回False。
-
flush
()- 刷新流的写入缓冲区(如果适用)。这对只读和非阻塞流不起作用。
-
readable
()- 如果可以读取流,则返回
True
。否则为False
,且 read() 将引发OSError
错误。
- 如果可以读取流,则返回
-
readline(size=-1)
- 从流中读取并返回一行。如果指定了 size,将至多读取 size 个字节。
-
readline(hint=-1)
- 从流中读取并返回包含多行的列表。可以指定 hint 来控制要读取的行数;
- 如果(以字节/字符数表示的)所有行的总大小超出了 hint 则将不会读取更多的行。
-
seek(offset, whence=SEEK_SET)
- 将流位置修改到给定的字节 offset。
- offset 将相对于由 whence 指定的位置进行解析。
- whence 的默认值为 SEEK_SET。whence 的可用值有:
- SEEK_SET 或 0,等同于流的开头(默认值);offset 应为零或正值。
- SEEK_CUR 或 1,等同于当前流的位置;offset 可以为负值
- SEEK_END 或 2,等同于流的末尾;offset 通常为负值
- 返回新的绝对位置。
-
seekable()
- 如果流支持随机访问则返回True。如果为
False
,则使用seek(),tell()
和truncate()
将引发OSError
。
- 如果流支持随机访问则返回True。如果为
-
tell()
- 返回当前流的位置。
-
truncate(size=None)
- 将流的大小调整为给定的 size 个字节(如果未指定 size 则调整至当前位置)。当前的流位置不变。
- 这个调整操作可扩展或减小当前文件大小。在扩展情况下,新文件区域的内容取决于系统平台(在大多数系统上,额外的字节会填充为0)。返回新的文件大小。
- 3.5之后:Windows在扩展时将文件填充为0。
-
writelines(lines)
- 将流列表写入到流,不会添加行分隔符,因此通常所提供的每一行都带有末尾行分隔符。
-
writable()
- 如果流支持写入则返回
True
。如果为False
,则write()
和truncate()
将引发OSError
。
- 如果流支持写入则返回
-
__del__()
- 为对象销毁进行准备。
IOBase
提供来此方法的默认实现,该实现会调用实例的close()
方法。
- 为对象销毁进行准备。
class io.RawIOBase
-
原始二进制I/O的基类。它继承自
IOBase
。 没有公共构造器。 -
原始二进制 I/O 通常提供对下层 OS 设备或 API 的底层级访问,而不尝试将其封装到高层级的基元中。
-
在
IOBase
的属性和方法之外,RawIOBase
还提供了下列方法:-
read(size=-1)
- 从对象中读取 size 个字节并将其返回。如果 size 未指定或为 -1,则返回所有字节直到 EOF(文件结束符)。在其他情况下,仅会执行一次系统调用。如果操作系统调用返回字节数少于 size,则此方法也可能返回少于 size 个字节。
- 如果返回 0 个字节而 size 不为 0,这表明到达文件末尾。如果处于非阻塞模式并且没有更多字节可用,则会返回
None
。 read()
默认调用的话实现会跳转至readall()
或readinto()
。
-
readall()
- 从流中读取并返回所有字节直到 EOF,如果有必要将对流执行多次调用。
-
readinto(b)
- 将字节数据读入预先分配的可写
bytes-like object
b,并返回读取的字节数。 例如,b可以使一个bytesarry
。 如果对象处理非阻塞模式并且没有更多字符可用,则返回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
实现不应当继承自RawIOBbase
实现,而要包装一个该实现,正如BufferedWriter
和BufferedReader
所做的那样。 -
BufferedIOBase
在IOBase
的现有成员以外还提供了或重载了下列方法和属性-
raw
- 由
BufferedIOBase
处理的下层原始流(RawIOBase
的实例)。它不是BufferedIOBase
API 的组成部分并且不存在于某些实现中。
- 由
-
detach()
- 从缓冲区分离出下层原始流并将其返回。
- 在原始流被分离后,缓冲区将处于不可用的状态。
BytesIO
没有detach()
方法返回的单独原始流概念。它将引发UnsupportedOperation
。
-
read(size=-1)
- 读取并返回最多 size 个字节。如果省略此参数则返回
None
,如果参数为负值则读取并返回所有数据直到 EOF。如果流已经到达 EOF 则返回一个空的bytes
对象。 - 如果此参数为正值,并且下层原始流不可交互,则可能发起多个原始读取以满足字节计数(直到先遇到 EOF)。但对于可交互原始流,则将至多发起一个原始读取,并且简短的结果并不一位置已经到达 EOF。
BlockingIOError
会在下层原始流不处于阻塞模式,并且当前没有可用数据时被引发。
- 读取并返回最多 size 个字节。如果省略此参数则返回
-
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
会在下层原始流开始不处于阻塞模式,并且当前没有可用数据时被引发。
- 将字节数据读入预先分配的可写
-
write(b)
- 写入给定的
bytes-like object
b,并返回写入的字节数(总是等于 b 的字节长度),因为如果写入失败则会引发OSError
。根据具体实现的不同,这些字节可能被实际写入下层流,或是出于运行效率和冗余等考虑而暂存于缓冲区。 - 当出于非阻塞模式时,如果需要将数据写入原始流但它无法在不阻塞的情况下接受所有数据则引发错误
BlockingIOError
。 - 调用者可能会在此方法返回后释放或改变 b,因此该实现应当仅在方法调用期间访问 b。
- 写入给定的
-
原始文件 I/O
class io.FileIO(name, mode='r', closefd=True, opener=None)
-
FileIO
代表在 OS 层级上包含文件的字节数据。它实现来RawIOBase
接口(因而也实现了IOBase
接口)。 -
name
可以使以下两项之一:- 代表将被打开的文件路径的字符串或
bytes
对象。在此情况下 closefd 必须为 True(默认值)否则将会引发异常。 - 代表一个现有 OS 层级文件描述符的号码整数,作为结果的
FileIO
对象将可以访问该文件。当 FileIO 对象被关闭时此 fd也将被关闭,除非closefd
设置为False
。
- 代表将被打开的文件路径的字符串或
-
mode
- 可以为
'r','w','x' 或 'a'
分别表示读取(默认模式)、写入、排它性新建或添加(上面表格有讲)。 - 如果写入或添加模式打开的文件不存在将自动新建。
- 当以写入模式打开时文件将先清空。
- 以新建模式打开时如果文件已存在则将引发
FileExistsError
。以新建模式打开文件也意味着要写入,因此该模式的行为与'w'
类似。 - 在模式中附带
'+'
将允许同时读取和写入。
- 可以为
-
该类的
read()(当附带正值参数调用时),readinto() 和 write()
方法将只执行一次系统调用。 -
可以通过传入一个可调用对象作为 opener 来使用自定义文件打开器。然后通过调用 opener 并传入(name,flags)来获取文件对象所对应的下层文件描述符。opener必须返回一个打开文件描述符(传入
os.open
作为 opener 的结果在功能上将与传入None
类似)。 -
新创建的文件是
不可继承的
。 -
在 3.3 版本:增加了 opener 参数。增加来
'x'
模式。 -
在 3.4 版本:文件现在禁止继承。
-
除了来自
IOBase
和RawIOBase
的属性和方法之外,FileIO
还提供了下列数据属性:- mode
- 构造函数中给定的模式
- name
- 文件名。当构造函数中没有给定名称时,这是文件的文件描述符。
- mode
缓冲流
相比原始 I/O,缓冲 I/O 流提供了针对 I/O 设备的更高层级接口。
-
class
io.BytesIO
([initial_bytes])一个使用内存字节缓冲区的流实现。 它继承自
BufferedIOBase
。 在close()
方法被调用时将会丢弃缓冲区。可选参数 initial_bytes 是一个包含初始数据的 bytes-like object。BytesIO
在继承自BufferedIOBase
和IOBase
的成员以外还提供或重载了下列方法: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])在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
。BufferedReader
在继承自BufferedIOBase
和IOBase
的成员以外还提供或重载了下列方法:peek
([size])从流返回字节数据而不前移位置。 完成此调用将至多读取一次原始流。 返回的字节数量可能少于或多于请求的数量。read
([size])读取并返回 size 个字节,如果 size 未给定或为负值,则读取至 EOF 或是在非阻塞模式下读取调用将会阻塞。read1
([size])在原始流上通过单次调用读取并返回至多 size 个字节。 如果至少缓冲了一个字节,则只返回缓冲的字节。 在其他情况下,将执行一次原始流读取。在 3.7 版更改: size 参数现在是可选的。 -
class
io.BufferedWriter
(raw, buffer_size=DEFAULT_BUFFER_SIZE)一个提供对可读的序列型
RawIOBase
对象更高层级访问的缓冲区。 它继承自BufferedIOBase
。 当写入到此对象时,数据通常会被放入到内部缓冲区中。 缓冲区将在满足某些条件的情况下被写到下层的RawIOBase
对象,包括:当缓冲区对于所有挂起数据而言太小时;当flush()
被调用时当(为BufferedRandom
对象)请求seek()
时;当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
。该构造器会为在第一个参数中给定的可查找原始流创建一个读取器和定稿器。 如果省略 buffer_size 则使用默认的DEFAULT_BUFFER_SIZE
。BufferedRandom
能做到BufferedReader
或BufferedWriter
所能做的任何事。 此外,还会确保实现seek()
和tell()
。 -
class
io.BufferedRWPair
(reader, writer, buffer_size=DEFAULT_BUFFER_SIZE)一个带缓冲的 I/O 对象,它将两个单向
RawIOBase
对象 – 一个可读,另一个可写 – 组合为单个双向端点。 它继承自BufferedIOBase
。reader 和 writer 分别是可读和可写的RawIOBase
对象。 如果省略 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_SET
或0
: 从流的开始位置起查找(默认值);offset 必须为TextIOBase.tell()
所返回的数值或为零。 任何其他 offset 值都将导致未定义的行为。SEEK_CUR
或1
: “查找” 到当前位置;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 是一个可选的字符串,它指明编码格式和编码格式错误的处理方式。 传入'strict'
将在出现编码格式错误时引发ValueError
(默认值None
具有相同的效果),传入'ignore'
将忽略错误。 (请注意忽略编码格式错误会导致数据丢失。)'replace'
会在出现错误数据时插入一个替换标记 (例如'?'
)。'backslashreplace'
将把错误数据替换为一个反斜杠转义序列。 在写入时,还可以使用'xmlcharrefreplace'
(替换为适当的 XML 字符引用) 或'namereplace'
(替换为\N{...}
转义序列)。 任何其他通过codecs.register_error()
注册的错误处理方式名称也可以被接受。newline 控制行结束符处理方式。 它可以为None
,''
,'\n'
,'\r'
和'\r\n'
。 其工作原理如下:当从流中读取输入时,如果 newline 为None
,则会启用 universal newlines 模式。 输入中的行结束符可以为'\n'
,'\r'
或'\r\n'
,在返回给调用者之前它们会被统一转写为'\n'
。 如果参数为''
,也会启用通用换行模式,但行结束符会不加转写即返回给调用者。 如果它具有任何其他合法的值,则输入行将仅由给定的字符串结束,并且行结束符会不加转写即返回给调用者。将输出写入流时,如果 newline 为None
,则写入的任何'\n'
字符都将转换为系统默认行分隔符os.linesep
。如果 newline 是''
或'\n'
,则不进行翻译。如果 newline 是任何其他合法值,则写入的任何'\n'
字符将被转换为给定的字符串。如果 line_buffering 为True
,则当一个写入调用包含换行符或回车时将会应用flush()
。如果 write_through 为True
,对write()
的调用会确保不被缓冲:在TextIOWrapper
对象上写入的任何数据会立即交给其下层的 buffer 来处理。在 3.3 版更改: 已添加 write_through 参数在 3.3 版更改: 默认的 encoding 现在将为locale.getpreferredencoding(False)
而非locale.getpreferredencoding()
。 不要使用locale.setlocale()
来临时改变区域编码格式,要使用当前区域编码格式而不是用户的首选编码格式。TextIOWrapper
在继承自TextIOBase
及其父类的现有成员以外还提供了下列成员:line_buffering
是否启用行缓冲。write_through
写入是否要立即传给下层的二进制缓冲。3.7 新版功能.reconfigure
(**[, encoding][, errors][, newline][, line_buffering][, write_through]*)使用 encoding, errors, newline, line_buffering 和 write_through 的新设置来重新配置此文本流。未指定的形参将保留当前设定,例外情况是当指定了 encoding 但未指定 errors 时将会使用errors='strict'
。如果已经有数据从流中被读取则将无法再改变编码格式或行结束符。 另一方面,在写入数据之后再改变编码格式则是可以的。此方法会在设置新的形参之前执行隐式的流刷新。3.7 新版功能. -
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
。
性能
本节讨论所提供的具体 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和二进制数据之间进行转换。这在处理大量文本数据(如大型日志文件)时会变得非常明显。此外,由于使用的重构算法 TextIOWrapper.tell()
和 TextIOWrapper.seek()
都相当慢。
StringIO
是原生的内存 Unicode 容器,速度与 BytesIO
相似。
多线程
FileIO
对象是线程安全的,只要它们封装的操作系统调用(比如Unix下的 read(2)
)也是线程安全的。
二进制缓冲对象(例如 BufferedReader
, BufferedWriter
, BufferedRandom
和 BufferedRWPair
)使用锁来保护其内部结构;因此,可以安全地一次从多个线程中调用它们。
TextIOWrapper
对象不再是线程安全的。
可重入性
二进制缓冲对象( BufferedReader
, BufferedWriter
, BufferedRandom
和 BufferedRWPair
的实例)不是可重入的。虽然在正常情况下不会发生可重入调用,但仍可能会在 signal
处理程序执行 I/O 时产生。如果线程尝试重入已经访问的缓冲对象,则会引发 RuntimeError
。注意,这并不禁止其他线程进入缓冲对象。
上面的内容隐含地扩展到文本文件,因为 open()
函数会把缓冲对象封装在 TextIOWrapper
中。这包括标准流,因此也会影响内置函数 print()
。