文件操作
程序运行中经常需要把数据保存到文件,或者从文件读取数据。Python 通过内置的 open() 函数打开文件,返回一个文件对象,然后就可以对它进行读写操作了。正确理解文件模式和指针位置,并养成使用 with 语句的习惯,是写好文件操作代码的关键。
1. 打开文件
使用 open() 函数打开文件,常用形式只需要传入文件名和模式:
f = open('test.txt', 'r', encoding='utf-8')完整语法为:
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)常用参数说明:
file:文件路径,可以是相对路径或绝对路径。mode:文件打开模式,默认为'r'(只读文本模式)。encoding:文件编码,文本文件通常设置为'utf-8'。
如果文件无法打开,会抛出 OSError。文件使用完毕后,记得调用 close() 方法关闭文件对象。
2. 文件打开模式
mode 参数决定以什么方式打开文件,常用模式如下:
| 模式 | 说明 |
|---|---|
r | 只读,文件指针在开头(默认)。 |
w | 只写,若文件存在则清空内容,不存在则创建。 |
a | 追加,文件指针在末尾,不会清空已有内容。 |
x | 创建并写入,若文件已存在则报错。 |
b | 二进制模式,通常与 r、w、a 组合使用。 |
t | 文本模式(默认)。 |
+ | 更新模式,可读可写。 |
下面用最小示例演示几种常见模式的区别:
# 以只读模式打开文本文件
f = open('test.txt', 'r', encoding='utf-8')
print(f.read())
f.close()# 以写入模式打开,会清空原有内容
f = open('test.txt', 'w', encoding='utf-8')
f.write('Hello, Python!')
f.close()# 以追加模式打开,在文件末尾追加内容
f = open('test.txt', 'a', encoding='utf-8')
f.write('\n这是追加的一行。')
f.close()# 以二进制模式读取图片
f = open('photo.png', 'rb')
data = f.read()
print(len(data))
f.close()如果文件不存在,
r模式会报错,而w和a模式会自动创建文件。
3. 读取文件
3.1 read()
read(size) 从文件读取指定数量的字符或字节。如果不传参数或传入负数,则读取整个文件内容。
f = open('test.txt', 'r', encoding='utf-8')
content = f.read()
print(content)
f.close()只读取前 5 个字符:
f = open('test.txt', 'r', encoding='utf-8')
print(f.read(5))
f.close()3.2 readline()
readline() 每次读取一行,返回的字符串包含末尾的换行符 \n。
f = open('test.txt', 'r', encoding='utf-8')
line = f.readline()
while line:
print(line, end='')
line = f.readline()
f.close()3.3 readlines()
readlines() 一次性读取所有行,返回一个列表,每个元素是一行内容。
f = open('test.txt', 'r', encoding='utf-8')
lines = f.readlines()
print(lines)
f.close()3.4 直接迭代文件对象
文件对象本身是可迭代的,用 for 循环逐行读取更省内存:
f = open('test.txt', 'r', encoding='utf-8')
for line in f:
print(line, end='')
f.close()对于大文件,推荐用
for line in f的方式逐行读取,而不是一次性readlines()。
4. 写入文件
4.1 write()
write(str) 将字符串写入文件,返回写入的字符数。
f = open('test.txt', 'w', encoding='utf-8')
f.write('第一行\n')
f.write('第二行\n')
f.close()4.2 writelines()
writelines(sequence) 接收一个字符串序列(列表、元组等),把其中每个元素依次写入文件。注意:它不会自动添加换行符。
lines = ['第一行\n', '第二行\n', '第三行\n']
f = open('test.txt', 'w', encoding='utf-8')
f.writelines(lines)
f.close()使用
writelines()时,如果希望每条数据各占一行,需要手动在字符串末尾加上\n。
5. 文件指针位置
文件对象内部有一个指针,记录当前读写的位置。
5.1 tell()
tell() 返回当前指针位置。
f = open('test.txt', 'r', encoding='utf-8')
print(f.read(5))
print(f'当前位置: {f.tell()}')
f.close()5.2 seek()
seek(offset, whence) 移动文件指针。offset 表示偏移量,whence 表示起始位置:
0:从文件开头计算(默认)。1:从当前位置计算。2:从文件末尾计算。
在文本模式下,非零偏移时
whence只能使用0,即相对文件开头;二进制模式下可以使用1和2。
f = open('test.txt', 'r', encoding='utf-8')
f.seek(6, 0)
print(f.read())
f.close()二进制模式下从文件末尾偏移:
f = open('test.txt', 'rb')
f.seek(-5, 2)
print(f.read())
f.close()5.3 truncate()
truncate(size) 从文件开头截断到指定大小,超出部分会被删除。如果不传参数,则截断到当前指针位置。
f = open('test.txt', 'r+', encoding='utf-8')
f.truncate(10)
f.close()在 Windows 系统中,换行符
\r\n占 2 个字符。
6. 其他常用方法
6.1 close()
close() 关闭文件对象,释放系统资源。关闭后不能再进行读写操作。
f = open('test.txt', 'r', encoding='utf-8')
print(f.read())
f.close()
# 关闭后再读取会报错
# f.read() # ValueError: I/O operation on closed file6.2 flush()
flush() 把数据从 Python 的内部缓冲区立刻推送到操作系统,而不是等待文件关闭时自动刷新。
f = open('test.txt', 'w', encoding='utf-8')
f.write('立即写入')
f.flush()
# 此时即使不关闭文件,内容也已离开 Python 缓冲区
f.close()6.3 fileno()
fileno() 返回文件对象的整数描述符,常用于底层 I/O 操作。
f = open('test.txt', 'r', encoding='utf-8')
print(f.fileno())
f.close()6.4 isatty()
isatty() 判断文件是否连接到一个终端设备,比如命令行输入输出。
f = open('test.txt', 'r', encoding='utf-8')
print(f.isatty()) # False
f.close()7. 使用 with 语句管理文件
手动调用 close() 容易遗漏,而且一旦中间发生异常,文件可能不会被关闭。推荐用 with 语句,它会在代码块结束时自动关闭文件,即使发生异常也不例外。
with open('test.txt', 'r', encoding='utf-8') as f:
print(f.read())
# 出了 with 块,文件已经自动关闭等价于:
f = open('test.txt', 'r', encoding='utf-8')
try:
print(f.read())
finally:
f.close()写入文件时同样推荐用 with:
with open('test.txt', 'w', encoding='utf-8') as f:
f.write('使用 with 语句写入的内容')日常写文件操作代码时,优先使用
with语句,避免资源泄漏。
8. 二进制文件与编码
8.1 读写二进制文件
图片、音频、视频等非文本文件需要用二进制模式处理,数据以字节形式读写。
# 读取二进制文件
with open('photo.png', 'rb') as f:
data = f.read()
print(type(data)) # <class 'bytes'>
# 复制二进制文件
with open('photo.png', 'rb') as src:
with open('photo_copy.png', 'wb') as dst:
dst.write(src.read())8.2 中文编码
文本文件打开时建议显式指定 encoding='utf-8',否则在不同系统上可能使用默认编码,导致中文乱码。
with open('test.txt', 'w', encoding='utf-8') as f:
f.write('你好,Python!')
with open('test.txt', 'r', encoding='utf-8') as f:
print(f.read())读取文件时,如果编码不匹配,会抛出
UnicodeDecodeError。
9. 常用方法速查
| 方法 | 作用 |
|---|---|
open() | 打开文件,返回文件对象。 |
read(size) | 读取指定大小内容,默认读取全部。 |
readline() | 读取一行。 |
readlines() | 读取所有行并返回列表。 |
write(str) | 写入字符串。 |
writelines(seq) | 写入字符串序列。 |
tell() | 返回当前文件指针位置。 |
seek(offset, whence) | 移动文件指针。 |
truncate(size) | 截断文件到指定大小。 |
close() | 关闭文件对象。 |
flush() | 立即刷新缓冲区到文件。 |
fileno() | 返回文件描述符。 |
isatty() | 判断是否连接终端设备。 |
10. StringIO 和 BytesIO
除了文件对象,io 模块还提供了内存中的文本/字节流对象,方便像操作文件一样处理字符串和字节。
10.1 StringIO
StringIO 在内存中读写文本,适合临时拼接字符串。
from io import StringIO
f = StringIO()
f.write('Hello')
f.write(' ')
f.write('Python')
# 获取全部内容
print(f.getvalue()) # Hello Python也可以从字符串读取:
from io import StringIO
f = StringIO('Hello\nWorld\n')
for line in f:
print(line.strip())10.2 BytesIO
BytesIO 与 StringIO 类似,但操作的是字节。
from io import BytesIO
f = BytesIO()
f.write('中文'.encode('utf-8'))
print(f.getvalue()) # b'\xe4\xb8\xad\xe6\x96\x87'11. 序列化
把内存中的对象保存到文件,或通过网络传输,需要先把对象转成字节序列,这个过程叫序列化;反过来的过程叫反序列化。
11.1 JSON 序列化
JSON 是最常用的序列化格式,Python 内置了 json 模块。
import json
data = {'name': 'juzicoding', 'age': 18}
# 序列化
json_str = json.dumps(data, ensure_ascii=False)
print(json_str) # {"name": "juzicoding", "age": 18}
# 反序列化
obj = json.loads(json_str)
print(obj) # {'name': 'juzicoding', 'age': 18}json.dump() 和 json.load() 可以直接操作文件对象。
import json
data = {'name': 'juzicoding', 'age': 18}
with open('data.json', 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False)
with open('data.json', 'r', encoding='utf-8') as f:
print(json.load(f))11.2 pickle 序列化
pickle 可以序列化 Python 几乎所有的对象,但格式是 Python 专用的,且存在安全风险,不要反序列化不信任来源的数据。
import pickle
data = {'name': 'juzicoding', 'age': 18}
# 序列化
b = pickle.dumps(data)
print(b)
# 反序列化
print(pickle.loads(b))跨语言共享数据优先用 JSON;只在 Python 内部使用时才考虑 pickle。
总结
Python 文件操作的核心是 open() 函数和文件对象方法。关键要点:
- 根据需求选择合适的模式:
r读、w写、a追加、b二进制、+读写。 - 读取文件优先用
for line in f逐行遍历,避免大文件占用过多内存。 - 写入文件注意
w会清空原内容,a会追加,writelines()不会自动换行。 - 文件指针通过
tell()和seek()控制,文本模式下seek()只能从文件开头偏移。 - StringIO/BytesIO 可以在内存中像文件一样操作字符串和字节。
- JSON 适合跨语言序列化,pickle 适合 Python 内部使用。
- 日常代码中优先使用
with语句管理文件,确保文件在使用后自动关闭,即使发生异常也安全可靠。