文件读写
本教程共 70 篇 · 第 44 篇 · 更新于 2026-07-22 · 约 6 分钟阅读
44. 文件读写
本节目标:掌握
open()的各种模式,学会安全地读写文本和二进制文件,理解文件指针的运作原理。
程序的数据往往需要持久化保存。内存里的变量断电就消失,文件能把数据留在磁盘上。Python 的文件操作简单直观,但有几个细节不注意就会踩坑。
打开文件:open()
f = open('data.txt', 'r', encoding='utf-8')
content = f.read()
f.close()
open() 的参数:
- 第一个参数:文件路径。
- 第二个参数:模式(mode)。
encoding:文本文件的编码,默认是平台相关的(Windows 常是 GBK,Linux/macOS 是 UTF-8)。建议始终显式指定encoding='utf-8'。
常用模式:
| 模式 | 含义 |
|---|---|
'r' | 只读(默认) |
'w' | 只写,文件存在则清空 |
'x' | 只写,文件存在则报错 |
'a' | 追加,写在文件末尾 |
'b' | 二进制模式(如 'rb'、'wb') |
'+' | 读写模式(如 'r+'、'w+') |
Warning
'w'模式会无条件清空已有内容。如果你想「没有则创建,有则追加」,用'a'。如果「有则报错,没有才创建」,用'x'。
用 with 语句管理文件
上面的例子有隐患:如果 read() 抛异常,f.close() 不会执行,文件句柄泄露。
正确做法是用 with:
with open('data.txt', 'r', encoding='utf-8') as f:
content = f.read()
# 离开 with 块,f 自动关闭
with 利用了「上下文管理器」协议。无论 with 块里是否发生异常,f.close() 都会被调用。
Tip养成习惯:只要打开文件,就用
with。这是 Python 社区的最佳实践,没有例外。
读取文件的方法
read():一次性读完
with open('data.txt', 'r', encoding='utf-8') as f:
content = f.read()
小文件没问题。如果文件有几百 MB,read() 会把全部内容载入内存,可能导致程序崩溃。
readline():逐行读取
with open('data.txt', 'r', encoding='utf-8') as f:
while True:
line = f.readline()
if not line:
break
print(line.strip())
readline() 每次读一行,包括末尾的换行符 \n。用 strip() 去掉空白和换行。
直接迭代文件对象(推荐)
文件对象本身就是迭代器,逐行遍历最 Pythonic:
with open('data.txt', 'r', encoding='utf-8') as f:
for line in f:
print(line.strip())
内存占用极低,因为每次只处理一行。这是读取大文件的标准做法。
readlines():读成列表
with open('data.txt', 'r', encoding='utf-8') as f:
lines = f.readlines()
返回一个列表,每个元素是一行文本(含换行符)。适合需要对全部行做随机访问的场景。
写入文件
lines = ['第一行', '第二行', '第三行']
with open('output.txt', 'w', encoding='utf-8') as f:
for line in lines:
f.write(line + '\n')
write() 不会自动加换行符,需要手动写 \n。
如果想一次性写入多行,用 writelines():
with open('output.txt', 'w', encoding='utf-8') as f:
f.writelines(line + '\n' for line in lines)
Note
writelines()不会自动加换行符,传入的序列里每个元素是什么样子,它就原样写入。这个名字有点误导,其实它不会「写行」,只是「批量写入」。
二进制文件
图片、视频、压缩包等非文本文件,必须用二进制模式读写:
# 复制一个图片文件
with open('source.jpg', 'rb') as src:
data = src.read()
with open('copy.jpg', 'wb') as dst:
dst.write(data)
二进制模式下,read() 返回 bytes 对象,write() 接受 bytes 对象。不要指定 encoding。
Warning文本模式(
'r'/'w')和二进制模式('rb'/'wb')不能混用。用文本模式读图片会损坏数据,用二进制模式读文本文件会得到bytes,需要手动decode()。
文件指针与 seek()
文件内部有一个「指针」,记录当前读写的位置。read() 后指针会移动,下次 read() 从新的位置开始。
with open('data.txt', 'r', encoding='utf-8') as f:
print(f.read(5)) # 读前 5 个字符
print(f.tell()) # 当前指针位置
f.seek(0) # 指针移回开头
print(f.read(5)) # 再次读前 5 个字符
tell():返回当前指针位置(文本模式下是字符数,二进制模式下是字节数)。seek(offset, whence):移动指针。whence为0表示从开头,1表示从当前位置,2表示从末尾。
with open('data.txt', 'rb') as f:
f.seek(-10, 2) # 移到末尾前 10 个字节
print(f.read())
Tip文本模式下
seek()的限制比较多(比如不能从当前位置或末尾相对移动),而且位置计算是按字符而非字节。需要灵活控制指针时,建议用二进制模式。
实战:合并多个文本文件
import glob
with open('merged.txt', 'w', encoding='utf-8') as out:
for filename in sorted(glob.glob('part_*.txt')):
with open(filename, 'r', encoding='utf-8') as part:
out.write(f"--- {filename} ---\n")
out.write(part.read())
out.write("\n")
嵌套 with 是合法的,外层文件保持打开,内层逐片读取。这种写法在批量处理文件时很常见。
小结
- 打开文件用
with,确保资源释放。 - 始终显式指定
encoding='utf-8',避免平台差异。 - 大文件用
for line in f逐行读取,别用read()。 - 二进制文件用
'b'模式,不指定编码。 seek()和tell()控制文件指针,二进制模式下最灵活。
文件操作看似简单,但编码问题和资源泄露是两大「杀手」。养成 with 的习惯、显式声明编码,能帮你避开 90% 的坑。
来源:参考了 runoob「Python3 文件方法」、liaoxuefeng「文件读写」、pythondoc「7. 输入与输出」等,改写后所得。