用 Python 临时文件安全替换 JSON 配置
【摘要】 使用同目录临时文件和 os.replace 写入 JSON,并验证序列化失败时的清理与原文件保护。
直接覆盖配置文件时,如果序列化失败或进程中断,原文件可能已经被截断。一个实用的做法是在目标目录先写临时文件,写完后再用 os.replace 替换目标。下面用 Python 标准库实现并验证这个过程。
实现
import json
import os
import tempfile
from pathlib import Path
def save_json(path, data):
path = Path(path)
temp_name = None
try:
with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', dir=path.parent, delete=False) as f:
temp_name = f.name
json.dump(data, f, ensure_ascii=False, indent=2)
f.write('\n')
f.flush()
os.fsync(f.fileno())
os.replace(temp_name, path)
temp_name = None
finally:
if temp_name is not None:
Path(temp_name).unlink(missing_ok=True)
if __name__ == '__main__':
with tempfile.TemporaryDirectory() as d:
target = Path(d) / 'config.json'
save_json(target, {'name': '示例', 'count': 2})
assert json.loads(target.read_text(encoding='utf-8')) == {'name': '示例', 'count': 2}
try:
save_json(target, {'bad': object()})
except TypeError:
pass
assert json.loads(target.read_text(encoding='utf-8'))['count'] == 2
assert list(Path(d).iterdir()) == [target]
print('写入和失败清理检查通过')
这里将临时文件放在目标文件同一目录,避免跨文件系统替换失败。json.dump 使用 UTF-8 和 ensure_ascii=False,便于查看中文;flush 和 fsync 将文件内容提交给操作系统,再关闭文件并替换。finally 在序列化等步骤失败时删除临时文件。目标父目录需要事先存在,写入权限也要足够。
验证
在临时目录执行脚本,先写入并读回字典,再故意传入不能 JSON 序列化的 object。第二次写入抛出 TypeError 后检查原数据仍存在、目录没有残留临时文件。本地 Python 运行输出“写入和失败清理检查通过”。这个测试覆盖序列化失败,不代表已经模拟断电或所有文件系统故障。
边界
os.replace 的替换语义依赖底层文件系统;同一文件系统上的原子替换可以减少读者看到半份文件的风险,但并不自动解决多进程并发写入,最后一个替换者仍可能覆盖其他更新。若需要严格的崩溃持久性,还应考虑目录项同步、平台差异和实际存储设备的行为。对于多用户并发配置,使用锁或事务型数据库更合适。临时文件的权限也可能与原文件不同,需要按应用需求明确设置。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)