Python open()函数详解:打开指定文件

Python 中,如果想要操作文件,首先需要创建或者打开指定的文件,并创建一个文件对象,而这些工作可以通过内置的 open() 函数实现。

open() 函数用于创建或打开指定文件,该函数的语法格式如下:

file = open(file_name [, mode[, buffering]])

此格式中,用 [] 括起来的部分,表示作为可选操作,可以使用,也可以省略。其中,各个参数所代表的含义如下:
  • file:表示要创建的文件对象。
  • file_mode:要创建或打开文件的文件名称,该名称要用引号(单引号或双引号都可以)括起来。需要注意的是,如果要打开的文件和当前执行的代码文件位于同一目录,则直接写文件名即可;否则,此参数需要指定打开文件所在的完整路径。
  • mode:可选参数,用于指定文件的打开模式。可选的打开模式如表 1 所示。如果不写,则默认以只读(r)模式打开文件。
  • buffing:可选参数,用于指定对文件做读写操作时,是否使用缓冲区(本节后续会详细介绍)。

open() 函数支持的文件打开模式如表 1 所示。

表 1 open 函数支持的文件打开模式
模式 意义 注意事项
r 只读模式打开文件,读文件内容的指针会放在文件的开头。 操作的文件必须存在。
rb 以二进制格式、采用只读模式打开文件,读文件内容的指针位于文件的开头,一般用于非文本文件,如图片文件、音频文件等。
r+ 打开文件后,既可以从头读取文件内容,也可以从开头向文件中写入新的内容,写入的新内容会覆盖文件中等长度的原有内容。
rb+ 以二进制格式、采用读写模式打开文件,读写文件的指针会放在文件的开头,通常针对非文本文件(如音频文件)。
w 以只写模式打开文件,若该文件存在,打开时会清空文件中原有的内容。 若文件存在,会清空其原有内容(覆盖文件);反之,则创建新文件。
wb 以二进制格式、只写模式打开文件,一般用于非文本文件(如音频文件)
w+ 打开文件后,会对原有内容进行清空,并对该文件有读写权限。
wb+ 以二进制格式、读写模式打开文件,一般用于非文本文件
a 以追加模式打开一个文件,对文件只有写入权限,如果文件已经存在,文件指针将放在文件的末尾(即新写入内容会位于已有内容之后);反之,则会创建新文件。  
ab 以二进制格式打开文件,并采用追加模式,对文件只有写权限。如果该文件已存在,文件指针位于文件末尾(新写入文件会位于已有内容之后);反之,则创建新文件。  
a+ 以读写模式打开文件;如果文件存在,文件指针放在文件的末尾(新写入文件会位于已有内容之后);反之,则创建新文件。  
ab+ 以二进制模式打开文件,并采用追加模式,对文件具有读写权限,如果文件存在,则文件指针位于文件的末尾(新写入文件会位于已有内容之后);反之,则创建新文件。  

文件打开模式,直接决定了后续可以对文件做哪些操作。例如,使用 r 模式打开的文件,后续编写的代码只能读取文件,而无法改动文件内容。

图 2 中,将以上几个容易混淆的文件打开模式的功能,做了很好的对比:

不同文件打开模式的功能
图 2 不同文件打开模式的功能
【例 1】默认打开 "a.txt" 文件。
#当前程序文件同目录下没有 a.txt 文件
file = open("a.txt")
print(file)
当以默认模式打开文件时,默认使用 r 权限,由于该权限要求打开的文件必须存在,因此运行此代码会报如下错误:

Traceback (most recent call last):
  File "C:\Users\mengma\Desktop\demo.py", line 1, in <module>
    file = open("a.txt")
FileNotFoundError: [Errno 2] No such file or directory: 'a.txt'


现在,在程序文件同目录下,手动创建一个 a.txt 文件,并再次运行该程序,其运行结果为:

<_io.TextIOWrapper name='a.txt' mode='r' encoding='cp936'>

可以看到,当前输出结果中,输出了 file 文件对象的相关信息,包括打开文件的名称、打开模式、打开文件时所使用的编码格式。

使用 open() 打开文件时,默认采用 GBK 编码。但当要打开的文件不是 GBK 编码格式时,可以在使用 open() 函数时,手动指定打开文件的编码格式,例如:

file = open("a.txt",encoding="utf-8")

此行代码表示,打开以 UTF-8 编码方式保存的 a.txt 文件。

open()是否需要缓冲区

众所周知,计算机外设(比如硬盘、网络)的 I/O 速度远远低于访问内存的速度,而程序执行 I/O 时要么将内存中的数据写入外设,要么将外设中的数据读取到内存,如果不使用缓冲,就必须等外设输入或输出一个字节后,内存中的程序才能输出或输入一个字节,这意味着内存中的程序大部分时间都处于等待状态。

内存中程序的读写速度很快,如果不使用缓冲,则程序必须等待外设进行同步读写。打个形象的比喻,就像在一条堵车的马路上开着跑车,必须等前面的车开一点,跑车才能前进一点。

因此,一般建议打开缓冲。在打开缓冲之后,当程序执行输出时,程序会先将数据输出到缓冲区中,而不用等待外设同步输出,当程序把所有数据都输出到缓冲区中之后,程序就可以去干其他事情了,留着缓冲区慢慢同步到外设即可;反过来,当程序执行输入时,程序会先等外设将数据读入缓冲区中,而不用等待外设同步输入。

在使用 open() 函数时,如果其第三个参数是 0(或 False),那么该函数打开的文件就是不带缓冲的;如果其第三个参数是 1(或 True),则该函数打开的文件就是带缓冲的,此时程序执行 I/O 将具有更好的性能。如果其第三个参数是大于 1 的整数,则该整数用于指定缓冲区的大小(单位是字节);如果其第三个参数为任何负数,则代表使用默认的缓冲区大小。

open()文件对象常用的属性

成功打开文件之后,可以调用文件对象本身拥有的属性获取当前文件的部分信息,其常见的属性为:
  • file.closed:判断文件是否己经关闭。
  • file.mode:返回被打开文件的访问模式。
  • file.name:返回文件的名称。

如下程序简单示范了如何打开文件和访问被打开文件的属性:
# 以默认方式打开文件
f = open('open_test.py')
# 访问文件的编码方式
print(f.encoding) # cp936
# 访问文件的访问模式
print(f.mode) # r
# 访问文件是否已经关闭
print(f.closed) # False
# 访问文件对象打开的文件名
print(f.name) # open_test.py
上面程序使用 open() 内置函数打开了 open_test.py 文件,接下来程序访问了被打开文件的各属性。运行上面程序,可以看到如下输出结果:

cp936
r
False
open_test.py

在打开文件之后,接下来就可以开始读取文件内容了。