必须用 with open() 确保文件自动关闭和缓冲区刷新;高可靠性场景需 flush() + os.fsync() 落盘;覆盖写入应采用临时文件+原子替换;write() 返回值须校验,fsync() 错误须主动捕获。

用 with open() 确保文件正确关闭
文件未正常关闭是数据损坏的常见源头,尤其在异常发生时。直接调用 open() 后忘记 close(),或在写入中途报错导致缓冲区未刷新,都可能让部分数据卡在内存里没落盘。
必须用 with 语句——它会在退出代码块时自动触发 __exit__,无论是否发生异常,都会调用 close() 并强制刷新缓冲区。
错误写法:
f = open("data.txt", "w")<br>f.write("hello")<br># 忘记 f.close(),或这里 raise Exception → 文件残留打开状态
正确写法:
with open("data.txt", "w") as f:<br> f.write("hello")<br># 自动 close(),且 flush() 已隐含执行
立即学习“Python免费学习笔记(深入)”;
显式调用 flush() 和 os.fsync() 控制落盘时机
Python 的 write() 默认只写入内核缓冲区,不保证立即写入磁盘。断电、系统崩溃或进程被强杀时,这部分缓冲数据就会丢失。
关键点:仅 flush() 不够,它只清空 Python 层和 C 库缓冲,把数据交给操作系统;要真正写入物理磁盘,还得调用 os.fsync()。
实操建议:
- 对可靠性要求高的场景(如日志、配置、交易记录),写完后加
f.flush()+os.fsync(f.fileno()) -
os.fsync()是阻塞操作,会影响性能,别滥用在高频小写入中 - Windows 上可用
os.fdatasync()(Python 3.9+),它跳过元数据同步,稍快一点
示例:
import os<br>with open("config.json", "w") as f:<br> f.write('{"mode": "prod"}')<br> f.flush()<br> os.fsync(f.fileno())避免覆盖写入导致的中间态损坏
直接 open(..., "w") 覆盖原文件,一旦写入中断(如磁盘满、权限变更),原文件就彻底没了,只剩一个截断或空文件。
更安全的做法是「先写新文件,再原子替换」:
- 用临时文件名写入(如
data.txt.tmp) - 写完并
fsync()后,调用os.replace()(Python 3.3+,POSIX 和 Windows 均原子) - 原文件名始终指向完整、可用的数据
- 临时文件可加
os.unlink()清理,但即使残留也不影响主流程
注意:os.rename() 在某些旧系统上不保证原子性,优先用 os.replace()。
检查 write() 返回值与异常捕获边界
write() 返回实际写入字节数,不等于你传入字符串长度,尤其涉及编码转换(如写入含 emoji 的 utf-8 字符串到 latin-1 文件)或磁盘空间不足时,可能只写了一半。
不能假设 write() 成功就等于数据完整落盘:
- 捕获
IOError、OSError(如[Errno 28] No space left on device) - 对比返回值与预期长度,不等则主动报错或重试
- 不要把多个
write()拆成独立语句却不检查每一步——中间失败会导致后续写入基于错误状态
例如:
expected = len(data)<br>actual = f.write(data)<br>if actual != expected:<br> raise RuntimeError(f"Short write: {actual}/{expected} bytes")
真正容易被忽略的是:fsync() 失败不会抛出异常,除非你主动检查它的返回值(它返回 None,出错时抛 OSError),而很多教程示例根本不处理这个分支。只要涉及关键数据,fsync() 后必须确认没出错。


















