文件打开与关闭:open()函数详解
文件操作,说白了就是跟磁盘上的数据打交道。我刚开始学Python时,觉得文件操作特别简单——不就是打开、读写、关闭嘛。但后来在项目中踩过几次坑,才发现这里面的门道还真不少。
今天咱们就好好聊聊文件打开与关闭这件事。你想想看,如果连门都开不对,后面的操作肯定全乱套。
open()函数:打开文件的第一把钥匙
Python里打开文件用的是open()函数。它的基本用法很简单:
file_object = open(file_name, mode)
第一个参数是文件名,第二个参数是打开模式。返回值是一个文件对象,后面所有的读写操作都靠它。
我个人习惯把文件名写成字符串,路径用正斜杠或者双反斜杠。比如:
f = open('data.txt', 'r') # 当前目录
f = open('./data/info.txt', 'r') # 相对路径
f = open('C:/Users/data.txt', 'r') # 绝对路径
注意:Windows路径里的反斜杠是转义符,要么用双反斜杠\\,要么用正斜杠/。我曾经因为这个bug排查了半小时,最后发现是路径写错了。
文件模式:r/w/a/r+/w+/a+ 到底怎么选?
模式这块,很多新手容易搞混。我整理了一张表,你一看就明白:
| 模式 | 可读 | 可写 | 文件存在 | 文件不存在 | 写入位置 |
|---|---|---|---|---|---|
| r | ✅ | ❌ | 正常打开 | 报错 | - |
| w | ❌ | ✅ | 清空内容 | 新建文件 | 文件开头 |
| a | ❌ | ✅ | 追加写入 | 新建文件 | 文件末尾 |
| r+ | ✅ | ✅ | 正常打开 | 报错 | 文件开头 |
| w+ | ✅ | ✅ | 清空内容 | 新建文件 | 文件开头 |
| a+ | ✅ | ✅ | 追加写入 | 新建文件 | 文件末尾 |
我来逐个说说我的使用心得:
- r模式:最常用。只读不写,安全可靠。我一般读取配置文件、日志分析都用它。
- w模式:写入新内容。注意它会清空原文件!我在项目中用它来生成报表,每次重新生成。
- a模式:追加写入。日志文件的最佳选择。不会覆盖已有内容,新内容直接加在末尾。
- r+模式:可读可写,但不会清空文件。说实话,这个模式我很少用,因为容易搞乱文件指针的位置。
- w+模式:可读可写,但会清空。我一般用来测试,或者需要同时读写新文件时用。
- a+模式:可读可写,追加模式。适合需要读取历史记录又要追加新数据的场景。
避坑指南:我曾经在项目里用w模式打开了一个重要的配置文件,结果文件内容全没了。从那以后,我养成了一个习惯——写文件前先确认模式,尤其是w和a的区别,一定要想清楚。
文件关闭:为什么不能忘?
打开文件后,一定要记得关闭。为什么?
第一,操作系统对同时打开的文件数量有限制。你打开不关,迟早会达到上限。
第二,写入操作可能还在缓冲区里,没真正写到磁盘。关闭文件时,缓冲区才会被刷新。
第三,文件锁的问题。有些系统里,文件被打开后其他程序就不能操作了。
正确的做法是:
f = open('data.txt', 'r')
# 读写操作...
f.close()
但这样写有个问题——如果中间代码报错了,close()可能根本执行不到。嗯,这里要注意。
with语句:最优雅的打开方式
Python提供了with语句,它是个上下文管理器。说白了,就是帮你自动处理打开和关闭。
with open('data.txt', 'r') as f:
content = f.read()
# 在这里做读写操作
# 离开with块后,文件自动关闭
你想想看,这样写多省心。不用记着close(),也不用担心异常导致文件没关闭。
我个人强烈建议:所有文件操作都用with语句。除非你有特殊需求,否则别用裸的open()。
小技巧:with语句可以同时打开多个文件:
with open('a.txt', 'r') as f1, open('b.txt', 'w') as f2:
data = f1.read()
f2.write(data)
这样两个文件都会在退出with块时自动关闭。
上下文管理器:with背后的原理
你可能好奇,with到底是怎么工作的?其实它依赖两个特殊方法:__enter__和__exit__。
当你写with open(...) as f时:
- Python调用
open()返回的文件对象的__enter__方法 __enter__返回文件对象本身,赋值给f- 执行
with块里的代码 - 无论代码是否报错,都会调用
__exit__方法 __exit__里执行了f.close()
说白了,这就是个语法糖。但Python的语法糖,用起来就是香。
你也可以自己写上下文管理器:
class MyFile:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
def __enter__(self):
self.file = open(self.filename, self.mode)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
# 返回False表示不处理异常,让上层处理
return False
# 使用
with MyFile('test.txt', 'r') as f:
print(f.read())
不过说实话,日常开发中直接用open()配合with就够了。自己写上下文管理器,一般是在封装数据库连接、网络连接这类资源时才会用到。
总结一下
文件打开与关闭,核心就三点:
- 选对模式:r/w/a/r+/w+/a+,根据需求来
- 记得关闭:或者直接用with语句
- 注意异常:文件不存在、权限不够、磁盘满了,这些都要考虑
我在项目中见过太多因为文件没关闭导致的问题了。有的程序跑着跑着报"Too many open files",有的数据写到一半断电了全丢了。这些坑,咱们能避就避。
下一节咱们聊聊文件读写操作,到时候会用到今天讲的这些知识。先把基础打牢,后面才能玩得转。