文件模式详解:r、w、a、r+、w+、a+ 模式的区别与使用场景
说实话,刚学文件操作那会儿,我也被这六种模式搞得晕头转向。r、w、a 还好理解,一加上 + 号就乱了。后来我在一个日志系统项目里踩了坑,才真正把这些模式吃透。
今天我就带你把这六种模式掰开揉碎,讲清楚。你想想看,搞懂了它们,以后写文件代码基本不会翻车。
一、先看一张图,心里有个谱
下面这张 SVG 图,是我自己画的。它把六种模式的核心逻辑串起来了。你看完这张图,再往下读,会轻松很多。
二、三种基础模式:r、w、a
这三种模式,是文件操作的「三原色」。其他带 + 号的,都是它们的变体。
1. r 模式(只读)
说白了就是:只能读,不能写。文件必须存在,否则直接报错 FileNotFoundError。
我个人习惯用 r 模式来读取配置文件、日志文件、数据文件。因为它最安全——你不可能手滑把文件内容改了。
# r 模式示例
with open('config.txt', 'r', encoding='utf-8') as f:
content = f.read()
print(content)
# 如果文件不存在,这里会直接崩溃
2. w 模式(只写)
注意了:w 模式会清空文件!不管你原来文件里有什么,一打开就全没了。
我曾经在写一个数据导出工具时,不小心用了 w 模式打开了一个重要的配置文件……嗯,那次教训挺深刻的。后来我养成了一个习惯:用 w 模式前,先确认文件是不是真的该被覆盖。
# w 模式示例
with open('output.txt', 'w', encoding='utf-8') as f:
f.write('这是新写入的内容\n')
# 原文件内容全部丢失
3. a 模式(追加)
a 模式不会清空文件。它把指针放在文件末尾,你写的内容会追加到后面。
我特别喜欢用 a 模式写日志。你想想看,日志文件本来就是越写越长,谁也不想每次启动程序就把历史日志清空吧?
# a 模式示例
with open('app.log', 'a', encoding='utf-8') as f:
f.write('2024-01-15 10:30:00 用户登录成功\n')
# 原有日志保留,新内容追加在末尾
三、三种增强模式:r+、w+、a+
带 + 号的模式,说白了就是「读写双修」。但它们的读写行为差异很大,我一个个讲。
4. r+ 模式(读写,文件必须存在)
r+ 模式不会清空文件。你可以读,也可以写。但写的时候,是从当前指针位置开始覆盖。
我在项目中遇到过这样一个场景:需要修改一个 JSON 文件的某个字段。用 r+ 模式打开,先读到内存里,修改完再 seek 回开头写入。嗯,这个模式很适合「原地修改」的场景。
# r+ 模式示例
with open('data.txt', 'r+', encoding='utf-8') as f:
content = f.read() # 先读
f.seek(0) # 指针回到开头
f.write('新内容') # 覆盖写入
5. w+ 模式(读写,会清空文件)
w+ 模式会清空文件。它和 w 模式一样,先把你原来的内容全删了,然后你才能读写。
说实话,我很少用 w+ 模式。因为如果你只是想写,用 w 就够了;如果你想读,文件都被清空了,读个啥?不过有一种情况例外:你需要在内存中模拟一个临时文件,先写后读。
# w+ 模式示例
with open('temp.txt', 'w+', encoding='utf-8') as f:
f.write('先写入一些内容\n')
f.seek(0)
print(f.read()) # 读取自己刚写的内容
6. a+ 模式(读写追加,不会清空)
a+ 模式是我个人最喜欢的「安全模式」。它不会清空文件,而且写的时候永远追加到末尾。读的时候,你需要手动把指针移到开头。
我曾经用 a+ 模式写过一个简单的聊天记录工具。每次收到消息就追加写入,用户想查看历史记录时,就把指针移到开头读取全部内容。完美。
# a+ 模式示例
with open('chat.log', 'a+', encoding='utf-8') as f:
f.write('新消息:你好\n')
f.seek(0)
all_content = f.read() # 读取全部历史记录
四、一张表总结所有模式
下面这张表,是我自己整理的。每次写文件操作前,我都会瞄一眼。建议你收藏。
| 模式 | 读 | 写 | 文件必须存在 | 是否清空 | 指针初始位置 | 典型场景 |
|---|---|---|---|---|---|---|
| r | ✅ | ❌ | ✅ 是 | ❌ 否 | 开头 | 读取配置文件 |
| w | ❌ | ✅ | ❌ 否(自动创建) | ✅ 是 | 开头 | 写入新文件 |
| a | ❌ | ✅ | ❌ 否(自动创建) | ❌ 否 | 末尾 | 追加日志 |
| r+ | ✅ | ✅ | ✅ 是 | ❌ 否 | 开头 | 修改已有文件 |
| w+ | ✅ | ✅ | ❌ 否(自动创建) | ✅ 是 | 开头 | 临时文件读写 |
| a+ | ✅ | ✅ | ❌ 否(自动创建) | ❌ 否 | 末尾 | 日志读写 |
五、避坑指南
最后,分享几个我踩过的坑。你记住了,以后能省不少时间。
- 我曾经用 r+ 模式打开一个文件,读完之后直接写,结果发现写的内容覆盖了原来的内容,而不是追加。原因很简单:读完之后指针在末尾,写的时候就从末尾开始覆盖了。解决方案:用 seek(0) 回到开头,或者用 a+ 模式。
- 我曾经在 w 模式下忘记备份原文件,结果数据全丢了。现在我的习惯是:用 w 模式前,先 copy 一份备份。
- 我曾经以为 a+ 模式可以随意读写,结果发现写操作永远在末尾。想读的时候必须手动 seek(0)。这不是 bug,是设计如此。
好了,文件模式的六种模式,今天就讲到这里。你只要记住一句话:读用 r,写用 w,追加用 a,需要同时读写就加 +。 然后根据文件是否必须存在、是否允许清空,选对模式就行。
下次写文件操作时,不妨先问问自己:这个文件必须存在吗?允许清空吗?需要同时读写吗?三个问题问完,模式自然就选对了。