一、 引言
在操作一个文件前,大部分情况需要先打开文件,才能进行,在Python中使用内置函数open来打开一个文件。open函数是Python的一个内置函数,io模块 定义的函数open是该内置函数的同义词(这是Python官网中关于io.open函数的说明,原文如下: “This is an alias for the builtin open() function”。这里的this是指io.open),open函数相关常规的操作方式与C语言的fopen函数类似度比较高。
二、 函数调用语法及参数释义
1. 语法:
open(file, mode =‘r’, buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
2. 参数说明:
open函数的参数老猿认为重要的就是file、mode,这个与c语言的fopen的参数非常类似,其他参数老猿就不展开细说。
1)file参数:
Python官网是这样说的:“file 是一个 path-like object,表示将要打开的文件的路径(绝对路径或者当前工作目录的相对路径),也可以是要被封装的整数类型文件描述符。(如果是文件描述符,它会随着返回的 I/O 对象关闭而关闭,除非 closefd 被设为 False 。)”。
像open()函数返回的这种有个read()方法的对象,在Python中统称为file-like Object。除了file外,还可以是内存的字节流,网络流,自定义流等等。file-like Object不要求从特定类继承,只要写个read()方法就行。例如StringIO就是在内存中创建的file-like Object,常用作临时缓冲
对初学者来说,理解其为可以带路径的文件名就可以了,注意如果是windows的路径带有反斜杠,需要前面再加反斜杠,防止被Python转义,其实最好的办法就是用原始字符串,即在字符串前面加字母r。
如果是文件描述符,该文件描述符应是一个通过os.open打开文件返回的文件描述符。关于文件描述符老猿将在后面的文章单独介绍,大家也可以在网上自己查资料。
2)mode:
文件打开的读写模式,是一个可选字符串,用于指定打开文件的模 式,默认值是 ‘r’。相关取值及对应模式如下:
老猿认为该模式与 C语言中的文件模式很像,主要由两种属性组合而成:
文件的类型:分为文本文件、二进制文件,对应模式中的:t、b。其中t模式是缺省模式;
操作的类型:读、写、追加、更新模式,对应模式中的:r、w、a、x、+,分别对应:只读、写、追加写、排它性创建写、更新,其中r模式是缺省模式,w模式在文件存在时会截断文件清空内容将文件重置为长度为0的空文件,不存在时会创建文件,a模式在文件存在时不会清空内容,文件不存在时会创建文件,x模式是新加的模式,当一个文件已经存在时,以x模式打开会引发FileExistsError,文件不存在时会创建文件执行写入。
注意:以上模式除追加模式外打开文件写入内容时,在没有指定文件内容写入位置的情况下,写入的地方都是从文件开头的位置开始写入,并且在文件已经存在的情况下,写入内容会覆盖文件开头对应长度的内容。追加模式写入都会追加到文件末尾。
更新模式,实际上就是读写模式,对应模式中的+,在指定了r模式的情况下启用更新模式,则文件内容还可读写,但x模式在文件已经存在的情况下不能使用更新模式。’'r+'和’w+‘之间有个重要差别:后者截断文件,而前者不会这样做。
默认模式为’rt’,这意味着将把文件视为经过编码的Unicode文本,因此将自动执行解码和编码,且默认使用UTF-8编码。要指定其他编码和Unicode错误处理策略,可使用关键字参数encoding和errors。
3)buffering:
是可选参数,用于设置缓冲策略。传递0以关闭缓冲(仅允许在二进制模式下),1选择行缓冲(仅在文本模式下可用),并且>1的整数以指示固定大小的块缓冲区的大小(以字节为单位)。如果没有给出 buffering 参数或值为-1,则默认缓冲策略如下:
二进制文件以固定大小的块进行缓冲;缓冲区的大小尝试底层设备的“块大小”或使用 io.DEFAULT_BUFFER_SIZE参数定义的大小。在许多系统上,缓冲区的长度通常为4096或8192字节。
“交互式”文本文件( isatty() 返回 True 的文件)使用行缓冲。其他文本文件使用上述用于二进制文件的策略。
4)encoding:
在文本模式,如果 encoding 没有指定,则根据平台环境来决定使用本地编码,本地编码可以通过import locale模块后,使用 locale.getpreferredencoding(False) 来获取。二进制文件不需要设置 encoding参数;
5)errors:
是一个可选的字符串参数,用于指定如何处理编码和解码错误,由于二进制文件不能指定编码方式,因此该参数不能在二进制模式下使用。错误类型包括:
• ‘strict’ :如果存在编码错误,会引发 ValueError 异常。 默认值 None 具有相同的效果。
• ‘ignore’: 忽略错误,请注意,忽略编码错误可能会导致数据丢失。
• ‘replace’: 会将替换标记(例如 ‘?’ )插入有错误数据的地方。
• ‘surrogateescape’ :将表示任何不正确的字节作为Unicode专用区中的代码点,范围从U+DC80到U+DCFF。当在写入数据时使用 surrogateescape 错误处理程序时,这些私有代码点将被转回到相同的字节中。这对于处理未知编码的文件很有用。
• ‘xmlcharrefreplace’:只有在写入文件时才支持 ,编码不支持的字符将替换为相应的XML字符引用 &#nnn;。
• ‘backslashreplace’: 用Python的反向转义序列替换格式错误的数据。
• ‘namereplace’ 在文件写入时用 \N{…} 转义序列替换不支持的字符。
6)newline:
换行符,用于 控制识别换行符和换行符读写的转换方式,它仅适用于文本模式,可以是 None、空字符串’’、’\n’、’\r’、 ‘\r\n’以及其他合法的字符串。它的工作原理:
• 官网翻译:“从流中读取输入时,如果 newline 为 None,则启用通用换行模式。输入中的行可以以 ‘\n’,’\r’ 或 ‘\r\n’ 结尾,这些行结尾符被转换成 ‘\n’ 。如果它是 ‘‘或引号标识的一个字符串,则启用通用换行模式,但行结尾将直接返回给访问者。如果它具有任何其他合法值,则输入行仅由给定字符串终止,并且行结尾将返回给给文件访问方”。老猿理解为:
所有换行符都用来判断一个文本的行是否结束,差别是关于换行符读取后怎么进行转换存入到读入的缓冲中;
如果换行符是通用换行模式,则’\n’,’\r’ 或 ‘\r\n’都可以作为行 结尾,并且读取行时,这些符号被转换成’\n’读入缓冲中;
如果该处填空字符串,则读取行的处理同’\n’,’\r’ 或 ‘\r\n’ ,只是’\n’,’\r’ 或 '\r\n’这些换行符不会进行转换,直接原样读入缓冲中。
• 将输出写入文件流时,如果 newline 为 None,则写入的任何 ‘\n’ 字符都将转换为系统默认行分隔符 os.linesep。如果 newline 是 ‘’ 或 ‘\n’,则不进行转换直接写入。如果 newline 是任何其他合法值,则写入的任何 ‘\n’ 字符将被转换为给定的字符串。
7)closefd:
这个参数老猿没有深入研究,大致认为是在第一个参数file不是文件名而是一个使用os.open打开的文件描述符时,在此指定当本open函数返回的文件对象关闭后,对应的文件描述符文件是否关闭,如果该参数为True则关闭传入进来的文件描述符,否则不关闭,该参数在第一个参数file为文件名时没有意义;
这个参数老猿没有完全弄明白作用,老猿猜想有种场景可以使用,就是第一个参数是通过外部接口传入的file是一个文件描述符,此时为了兼容通过文件名访问的功能,因此需要将其转换为文件对象进行操作,需要使用该参数确保传入的文件描述符不会关闭,以便外部接口后续能继续正常运行。
8)opener:
这个参数老猿没有深入研究,它是一个可调用的函数,该函数的目的是为了定制自己的文件打开操作函数,且这个文件打开操作函数的参数是open函数的第一个参数file和第二个参数mode,返回值是一个文件描述符(即通过os.open返回的类型),系统默认是调用的就是os.open,所以该参数传os.open与传None是相同的结果。
老猿没有弄明白这个参数opener的作用,可能在操作者需要深度控制文件访问逻辑时使用。
三、 函数返回结果
如果文件成功打开, open() 函数所返回的 file object 类型取决于所用模式。 当使用 open() 以文本模式 (‘w’, ‘r’, ‘wt’, ‘rt’ 等) 打开文件时,它将返回 io.TextIOBase 的一个子类 。 当使用缓冲以二进制模式打开文件时,返回的类是 io.BufferedIOBase 的一个子类。 具体的类会有多种:在只读的二进制模式下,它将返回 io.BufferedReader;在写入二进制和追加二进制模式下,它将返回 io.BufferedWriter,而在读/写模式下,它将返回 io.BufferedRandom。 当禁用缓冲时,则会返回原始流,即 io.RawIOBase 的一个子类 io.FileIO。
如果该文件不能打开,则触发 OSError及相关异常。
本节详细介绍了Python内置函数open(同时也是io.open的同义词)的相关调用语法及参数,相关参数有些内容老猿也没有完全弄清楚。