在开发过程中,开发者常常需要对文件执行读写操作,仅以此文记录读写文件的常规用法。
打开和关闭文件
Python 的内建函数 open 可以打开一个文件,可返回一个文件对象 TextIOWrapper(也称文件句柄)。打开的文件应当及时关闭,否则过多的文件对象容易造成内存占用,导致程序运行内存不足。按照是否调用文件对象的 close 方法,有两种打开和关闭文件的代码书写方式:
- 显式 close
- 隐式 close
显式 close
1
2
3
4
5
6
7
| def open1():
f = open('./students.dat')
try:
lines = f.readlines()
print(lines)
finally:
f.close()
|
隐式 close
1
2
3
4
| def open2():
with open('./students.dat') as f:
lines = f.readlines()
print(lines)
|
支持 with 语句的对象需要实现 __enter__ 和 __exit__ 两个方法,其中 TextIOWrapper 类实现了 __exit__ 方法,IOBase 类实现了 __enter__ 方法。
上述两个函数的作用相同,都是用于打开 students.dat 文件并打印所有的行。
open 函数
内建函数 open 的签名如下:
1
2
3
4
5
6
7
8
9
10
| def open(
file: _OpenFile,
mode: OpenTextMode = ...,
buffering: int = ...,
encoding: str | None = ...,
errors: str | None = ...,
newline: str | None = ...,
closefd: bool = ...,
opener: _Opener | None = ...,
) -> TextIOWrapper: ...
|
- file:字符串文件路径或实现了
os.PathLike 抽象类的实例; - mode:打开模式,默认
r,可选; - buffering:设置缓冲策略,可选;
- encoding:编码格式,可选;
- errors:编码或解码发生错误时的错误信息,可选;
- newline:断行的方式,可用的参数值有
None、' '、'\n'、'\r' 和 '\r\n',可选; - closefd:必须为
True,否则报错,可选; - opener:自定义的打开器,调用的函数,返回一个文件描述符,可选;
os.PathLike 抽象类
os.PathLike 是一个抽象类,定义了 __fspath__ 方法,任何实现了 __fspath__ 方法的类的实例都可以作为 open 函数的 file 参数值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| import os
class MyFile(os.PathLike):
def __init__(self, filename) -> None:
self.filename = filename
def __fspath__(self):
return self.filename
def open3():
with open(MyFile('./students.dat')) as f:
lines = f.readlines()
print(lines)
|
mode 参数值
mode 参数值可为:
| Mode | |
|---|
'r' | 读打开(默认) |
'w' | 读打开,若文件不存在则创建,若文件存在则会清空文件内容 |
'x' | 以独占的方式创建文件,如果文件已存在则报错 |
'a' | 以追加的形式打开文件,文件不存在会创建,文件存在的话,不会清空文件内容 |
't' | 文本模式(默认) |
'b' | 二进制打开文件 |
'+' | 以更新的方式打开文件 |
f.close 方法
当文件对象调用 close 方法后,对象的 closed 属性会置为 True,也可以通过该属性可以检查文件对象是否关闭。
1
2
3
4
| def view_f_closed():
f = open('./students.dat')
f.close()
print(f.closed)
|
读写文件
文件对象中有如下几个方法可用于读取文件内容:
文件对象中有如下几个方法可用于写入文件内容:
编码问题
若文件中存在中文,需要指定 encoding 参数的值,如:
1
2
3
4
| def read_chinese():
with open('./students.zh-cn.dat', encoding='utf-8') as f:
lines = f.readlines()
print(lines)
|
遍历文件所有的行
下面列表读取文件所有的行的几种方式。
方式 1
1
2
3
4
5
6
| def iterate_lines1():
with open('./students.dat', mode='r') as f:
line = f.readline()
while line != '':
print(line, end='')
line = f.readline()
|
方式 2
1
2
3
4
5
| def iterate_lines2():
with open('./students.dat', mode='r') as f:
lines = f.readlines()
for line in lines:
print(line, end='')
|
方式 3
1
2
3
4
| def iterate_lines3():
with open('./students.dat', mode='r') as f:
for line in f:
print(line, end='')
|
总结
本文的完整代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
| import os
def open1():
f = open('./students.dat')
try:
lines = f.readlines()
print(lines)
finally:
f.close()
def open2():
with open('./students.dat') as f:
lines = f.readlines()
print(lines)
class MyFile(os.PathLike):
def __init__(self, filename) -> None:
self.filename = filename
def __fspath__(self):
return self.filename
def open3():
with open(MyFile('./students.dat')) as f:
lines = f.readlines()
print(lines)
def view_f_closed():
f = open('./students.dat')
f.close()
print(f.closed)
def read_chinese():
with open('./students.zh-cn.dat', encoding='utf-8') as f:
lines = f.readlines()
print(lines)
def iterate_lines1():
with open('./students.dat', mode='r') as f:
line = f.readline()
while line != '':
print(line, end='')
line = f.readline()
def iterate_lines2():
with open('./students.dat', mode='r') as f:
lines = f.readlines()
for line in lines:
print(line, end='')
def iterate_lines3():
with open('./students.dat', mode='r') as f:
for line in f:
print(line, end='')
if __name__ == '__main__':
print('书写方式 1:')
open1()
print('书写方式 2:')
open2()
print('实现了 os.PathLike 抽象类')
open3()
print('调用 f.close 后:')
view_f_closed()
print('遍历所有的行 1:')
iterate_lines1()
print('遍历所有的行 2:')
iterate_lines2()
print('遍历所有的行 3:')
iterate_lines3()
print("读取中文:")
read_chinese()
|
运行输出为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| 书写方式 1:
['xiaoming\n', 'xiaohong\n', 'xiaolei\n', 'xiaopang\n']
书写方式 2:
['xiaoming\n', 'xiaohong\n', 'xiaolei\n', 'xiaopang\n']
实现了 os.PathLike 抽象类
['xiaoming\n', 'xiaohong\n', 'xiaolei\n', 'xiaopang\n']
调用 f.close 后:
True
遍历所有的行 1:
xiaoming
xiaohong
xiaolei
xiaopang
遍历所有的行 2:
xiaoming
xiaohong
xiaolei
xiaopang
遍历所有的行 3:
xiaoming
xiaohong
xiaolei
xiaopang
读取中文:
['小明\n', '小红\n', '小磊\n', '小胖\n']
|
本文可总结为以下几点:
- 打开文件后,应该及时关闭。如果不想显式地调用
close 方法,推荐使用 with 语句; open 函数的 mode 参数指定了文件打开的模式,mode 参数的几个可选值非常重要;- 列举了几个读写文件的常用方法,如读的
read、readline 和 readlines;写的 write 和 writelines; - 3 种遍历文件所有行的方式;