简介
不管是打开一个文档,查看一张图片,还是观看一部电影,本质上都是在进行文件操作。这项技能非常实用,在许多场合都能用上。比如保存程序的输出到日志文件中;在爬虫中批量下载网页内容等。在本文中,我们会介绍文件操作的相关知识。
文件访问模式
在介绍如何打开文件之前,首先介绍下文件访问模式,不同的访问模式具有不同的功能:
模式 | 描述 |
---|---|
t | 文本模式 (默认) |
x | 写模式,新建一个文件,如果该文件已存在则会报错 |
b | 二进制模式 |
+ | 打开一个文件进行更新(可读可写) |
U | 通用换行模式(不推荐 |
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等 |
w | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等 |
w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写 |
其中常用的有r
、w
、a+
等。
打开文件
如果想打开某个文件,可以按照如下格式:
1 2 3 4 |
变量 = open(文件地址, 打开模式, encoding=编码值) some code ... 变量.close() |
通过open()
打开一个文件,其中指定该文件的位置、打开模式和编码方式,不指定编码可省略。最后通过close()
关闭整个文件释放内存。还有另外一种方式打开文件,格式如下:
1 2 3 |
with open(文件地址, 打开模式, encoding=编码值) as f: some code ... |
这种方式就不需要显示的关闭文件,当with
关键字中的代码块运行完后,文件自动关闭释放内存。所以推荐使用这种打开文件的方式。
读取文件
有三种方法读取文件:
- read():一次性读取全部内容;
- readline():读取一行内容;
- readlines():读取每行内容,并将它们放到一个列表中。
使用read()
方法读取文件,会将文件里面的内容一次性读取出来。它的格式如下:
1 2 3 |
with open(文件地址, 打开模式, encoding=编码值) as 变量1: 变量2 = 变量1.read() some code |
举个例子,在"F:\only_for_test"
目录下,有一个finthon.txt
文本文件,里面的内容是:
1 2 3 4 |
this is a txt file its file name is finthon finthon is my personal website welcome to my blog. |
我们可以编写如下代码:
1 2 3 |
with open(r'F:\only_for_test\finthon.txt', 'r') as f: data = f.read() print(data) |
结果为:
1 2 3 4 |
this is a txt file its file name is finthon finthon is my personal website welcome to my blog. |
如果希望每次只读一行,可以通过readline()
方法实现,它的格式为:
1 2 3 4 |
with open(文件地址, 打开模式, encoding=编码值) as 变量1: 存储第一行数据的变量 = 变量1.readline() 存储第二行数据的变量 = 变量1.readline() ... |
同样,我们可以输入以下代码:
1 2 3 4 5 6 7 8 9 10 11 |
with open(r'F:\only_for_test\finthon.txt', 'r') as f: data = f.readline() print(data) data = f.readline() print(data) data = f.readline() print(data) data = f.readline() print(data) data = f.readline() print(data) |
输出的结果为:
1 2 3 4 5 6 7 8 |
this is a txt file ----------- #该行是由\n产生的空行 its file name is finthon ----------- #该行是由\n产生的空行 finthon is my personal website ----------- #该行是由\n产生的空行 welcome to my blog. ----------- #该行是由print()产生的空行 |
程序每次都会打印一行内容出来,但是由于每行最后都是以换行符\n
结束,因此打印的时候会出现空白行,而第五次打印的时候因为没有内容了,相当于print('')
语句,所以产生了一个空白行。在交互式编程中,我们就能清楚看到:
1 2 3 4 5 6 7 8 9 10 11 12 |
>>>f = open(r'F:\only_for_test\finthon.txt', 'r') >>>f.readline() 'this is a txt file\n' >>>f.readline() 'its file name is finthon\n' >>>f.readline() 'finthon is my personal website\n' >>>f.readline() 'welcome to my blog.' >>>f.readline() '' >>>f.close() |
有没有觉得这种输出方式特别眼熟,如果你学习了迭代器,就会发现这里的f
实际上就是迭代器,因此可以通过next()
函数或者__next__()
方法实现:
1 2 3 4 5 6 |
>>>f = open(r'F:\only_for_test\finthon.txt', 'r') >>>next(f) 'this is a txt file\n' >>>f.__next__() 'its file name is finthon\n' ... |
如果希望将读取的每行内容全部放到一个列表中,格式如下:
1 2 3 |
with open(文件地址, 打开模式, encoding=编码值) as 变量1: 变量2 = 变量1.readlines() some code |
我们通过readlines()
方式将finthon.txt
文件中的内容读取到一个列表:
1 2 |
with open(r'F:\only_for_test\finthon.txt', 'r') as f: print(f.readlines()) |
结果为:
1 |
['this is a txt file\n', 'its file name is finthon\n', 'finthon is my personal website\n', 'welcome to my blog.'] |
既然知道f.readlines()
是一个列表,那么可以使用for
循环遍历其中的元素,执行如下代码:
1 2 3 |
with open(r'F:\only_for_test\finthon.txt', 'r') as f: for i in f.readlines(): print(i) |
结果为:
1 2 3 4 5 6 7 |
this is a txt file ----------- #该行是由\n产生的空行 its file name is finthon ----------- #该行是由\n产生的空行 finthon is my personal website ----------- #该行是由\n产生的空行 welcome to my blog. |
在使用readline()
和readlines()
的时候,一定要记得除了最后一行外,每行的最后都是以\n
结束。
写入文件
写入文件需要使用write()
方法,具体格式如下:
1 2 3 4 |
with open(文件地址, 打开模式, encoding=编码值) as 变量1: 变量2 = 要写入的数据 变量1.write(变量2) 变量1.close() |
比如我们想将如下数据写入一个叫ccc.txt
的文本文件中,
1 2 3 4 |
my name is ccc, I am from ecust, you can call me MrLonelyZC88, hello world. |
代码如下:
1 2 3 |
with open(r'F:\only_for_test\ccc.txt', 'w') as f: data = 'my name is ccc,\nI am from shanghai,\nyou can call me MrLonelyZC88,\nhello world.' f.write(data) |
结果如图:
如果想在文件后面追加内容的话,就要修改文件打开模式了。比如我们想再添加一句话
do not forget finthon.
,只需这样处理:
1 2 3 |
with open(r'F:\only_for_test\ccc.txt', 'a+') as f: data = '\ndo not forget finthon.' f.write(data) |
结果如图:需要注意的是,除了最后一行外,其他的每行最后都是以
\n
结束,起到换行作用。
删除文件
删除文件的格式如下:
1 2 |
import os os.remove(文件路径) |
现在我们来删除该ccc.txt
文件:
1 2 |
import os os.remove(r'F:\only_for_test\ccc.txt') |
执行代码后,文件就被删除了。在目录操作中我们也提到了必须先删除目录中的文件,然后才能删除该目录。
文件方法总结
将文件用到的方法总结如下:
方法 | 描述 |
---|---|
file.close() | 关闭文件。关闭后文件不能再进行读写操作 |
file.fileno() | 返回一个整型的文件描述符(file descriptor FD 整型), 可以用在如os模块的read方法等一些底层操作上 |
file.flush() | 刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入 |
file.isatty() | 如果文件连接到一个终端设备返回 True,否则返回 False |
file.next() | 返回文件下一行 |
file.read([size]) | 从文件读取指定的字节数,如果未给定或为负则读取所有 |
file.readline([size]) | 读取整行,包括 “\n” 字符 |
file.readlines([sizeint]) | 读取所有行并返回列表,若给定sizeint>0,返回总和大约为sizeint字节的行, 实际读取值可能比 sizeint 较大, 因为需要填充缓冲区 |
file.seek(offset[, whence]) | 设置文件当前位置 |
file.tell() | 返回文件当前位置 |
file.truncate([size]) | 从文件的首行首字符开始截断,截断文件为 size 个字符,无 size 表示从当前位置截断;截断之后后面的所有字符被删除,其中 Widnows 系统下的换行代表2个字符大小 |
file.write(str) | 将字符串写入文件,返回的是写入的字符长度 |
file.writelines(sequence) | 向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符 |
总结
本文详细地介绍了文件操作的相关知识,熟练掌握文件操作的技巧,选择合适的文件读取模式(读、写、增)很重要;使用readline()
和readlines()
的时候,一定要记得除了最后一行外,每行的最后都是以\n
结束。相信学完本文能够加强你处理文件的能力。