1. 文件操作基础
说到文件操作,这其实是编程里最基础也最实用的技能之一。我刚开始学Python那会儿,觉得文件读写不就是打开、读写、关闭嘛,有啥好学的?直到有一次做数据处理项目,因为模式选错了,把好不容易爬来的数据全给覆盖了……嗯,从那以后我再也不敢小看这几个模式了。
1.1 文件到底是什么?
说白了,文件就是存储在磁盘上的一段数据。它有个名字,有个路径,还有一堆属性(比如大小、修改时间)。在Python眼里,文件就是一个流——你可以往里面写数据,也可以从里面读数据。
我个人习惯把文件想象成一个盒子:
- 文本文件:盒子里装的是写好的文字,打开就能看懂
- 二进制文件:盒子里装的是0和1的编码,需要特定程序才能解读
核心概念:文件操作的三部曲——打开 → 读写 → 关闭。少一步都不行。
1.2 文本文件 vs 二进制文件
这两种文件类型,我经常被新手问到有什么区别。其实很简单:
| 对比项 | 文本文件 | 二进制文件 |
|---|---|---|
| 存储内容 | 字符(如字母、数字、符号) | 原始字节(0和1) |
| 打开方式 | 记事本就能看 | 需要对应软件(如图片查看器) |
| 常见类型 | .txt, .csv, .json, .html | .jpg, .mp3, .exe, .zip |
| Python模式 | 'r', 'w', 'a' 等(默认文本模式) | 'rb', 'wb', 'ab'(加b后缀) |
| 编码处理 | 自动处理换行符(\n ↔ \r\n) | 不做任何转换 |
我在项目中遇到过一个问题:用文本模式读取图片文件,结果图片全乱了。原因就是文本模式会自作主张地转换换行符,把二进制数据搞坏了。所以记住:处理非文本文件,一定要用二进制模式。
小技巧:如果你不确定文件类型,可以用 open(file, 'rb') 先读几个字节看看。二进制模式最安全,不会破坏数据。
1.3 文件打开模式详解
这部分是重点,也是坑最多的地方。Python提供了6种基本模式,我一个个说。
1.3.1 'r' 模式(只读)
最常用的模式。文件必须存在,否则报错。只能读,不能写。
# 读取文本文件
with open('notes.txt', 'r', encoding='utf-8') as f:
content = f.read()
print(content)
# 读取二进制文件
with open('image.jpg', 'rb') as f:
data = f.read()
注意:'r'模式下文件不存在会抛出 FileNotFoundError。我曾经在自动化脚本里忘了检查文件是否存在,结果半夜报警……
1.3.2 'w' 模式(只写)
写入模式。如果文件存在,会清空原有内容;如果不存在,会创建新文件。
# 写入文本
with open('output.txt', 'w', encoding='utf-8') as f:
f.write('这是新内容\n')
f.write('原有内容会被覆盖')
# 写入二进制
with open('data.bin', 'wb') as f:
f.write(b'\x00\x01\x02\x03')
避坑指南:我曾经不小心用'w'模式打开了一个重要的配置文件,结果内容全没了。所以用'w'之前,一定确认你真的想覆盖文件。
1.3.3 'a' 模式(追加)
追加模式。文件指针在末尾,写入的内容会追加到文件最后。不会清空原有内容。
# 追加日志
with open('log.txt', 'a', encoding='utf-8') as f:
f.write(f'[{datetime.now()}] 用户登录成功\n')
我个人特别喜欢用'a'模式写日志文件。每次运行程序,新日志自动追加到末尾,不会丢失历史记录。
1.3.4 'r+' 模式(读写)
可读可写。文件必须存在。写入时从文件开头覆盖,不会清空整个文件。
with open('data.txt', 'r+', encoding='utf-8') as f:
content = f.read() # 先读取
f.write('追加到末尾') # 写入在末尾(因为读完后指针在末尾)
注意:'r+'模式下,写入的位置取决于当前文件指针的位置。如果你先读了全部内容,指针就在末尾,写入就是追加。如果你seek到开头再写,就会覆盖开头的内容。
1.3.5 'w+' 模式(写读)
可写可读。会清空文件(如果存在)。可以写入后再读取。
with open('temp.txt', 'w+', encoding='utf-8') as f:
f.write('先写入内容\n')
f.seek(0) # 把指针移回开头
print(f.read()) # 读取刚才写入的内容
嗯,这里要注意:'w+'会清空文件,所以一般用于创建新文件并需要后续读取的场景。
1.3.6 'a+' 模式(追加读)
可追加可读。文件指针在末尾,但可以移动到开头读取内容。
with open('log.txt', 'a+', encoding='utf-8') as f:
f.write('新日志行\n')
f.seek(0) # 移到开头
all_logs = f.read() # 读取全部内容
1.4 模式对比速查表
| 模式 | 可读 | 可写 | 文件必须存在 | 清空文件 | 指针位置 |
|---|---|---|---|---|---|
| 'r' | ✅ | ❌ | ✅ | ❌ | 开头 |
| 'w' | ❌ | ✅ | ❌ | ✅ | 开头 |
| 'a' | ❌ | ✅ | ❌ | ❌ | 末尾 |
| 'r+' | ✅ | ✅ | ✅ | ❌ | 开头 |
| 'w+' | ✅ | ✅ | ❌ | ✅ | 开头 |
| 'a+' | ✅ | ✅ | ❌ | ❌ | 末尾 |
1.5 知识体系图
下面这张图帮你理清文件操作的核心逻辑:
1.6 实战建议
最后,分享几个我自己的经验:
- 用with语句:自动关闭文件,省心又安全。我从来不用裸open()。
- 指定编码:文本文件操作时,
encoding='utf-8'是标配。不然在不同系统上可能乱码。 - 先测试再覆盖:用'w'模式前,先备份或确认。我吃过亏,你懂的。
- 二进制模式不乱用:只有处理图片、音频等非文本文件时才用'b'模式。
一句话总结:文件操作不难,难的是选对模式。记住这张表,你就能避开90%的坑。