安全修改INI文件需先备份再原子替换:用shutil.copy2()保留元信息,备份名动态加时间戳或序号;写入前生成临时文件,用os.replace()原子替换;用configparser解析修改,校验编码与语法,并用filecmp.cmp()验证备份一致性。

用 shutil.copy2() 复制时保留原始文件属性
直接覆盖原文件风险高,一出错就丢数据。安全做法是先备份再写入,而 shutil.copy2() 比 shutil.copy() 多保留了修改时间、访问时间、权限等元信息,这对配置文件、日志文件尤其关键——比如某些服务会按修改时间判断配置是否更新。
不要用 shutil.copy(),它只复制内容,丢了时间戳和权限,后续排查问题时可能误判。
备份文件名必须带时间戳或序号,不能硬编码 "backup"
常见错误是把备份写成固定名,比如 "config.ini.bak",下次再跑脚本就会被覆盖,等于没备份。
正确做法是动态生成唯一备份名:
- 用
datetime.now().strftime("%Y%m%d_%H%M%S")加时间戳,如"config.ini.20260930_074522.bak" - 或检查同名备份是否存在,自动追加序号:
"config.ini.bak.1"→"config.ini.bak.2" - 别把备份和原文件放同一级目录又不加前缀,容易在递归处理时误伤备份文件
写入新内容前,先写到临时文件再原子替换
直接 open(..., "w") 覆盖原文件,中途出异常(如磁盘满、断电)会导致原文件变空或损坏。
更稳妥的流程是:
- 读取原文件内容,处理后写入一个临时路径,例如
"config.ini.tmp" - 调用
os.replace(temp_path, original_path)—— 这个操作在大多数系统上是原子的,要么全成功,要么原文件不受影响 - 确认替换成功后,再删掉临时文件;失败则保留原文件,临时文件可人工检查
注意:os.rename() 在 Windows 上跨分区会失败,os.replace() 才是跨平台安全选择。
立即学习“Python免费学习笔记(深入)”;
INI 文件要特别注意编码识别和段落键值匹配
批量改 .ini 时,简单 str.replace() 极易误伤:比如把 "IP=192.168.1.100" 中的 "1" 替成 "2",结果变成 "IP=192.168.2.200"。
真正安全的做法是用 configparser 加载、修改、再写回:
- 用
configparser.ConfigParser(allow_no_value=True)初始化,避免因注释格式报错 - 调用
read_file()时传入encoding参数,优先尝试"utf-8-sig",失败再 fallback 到"gbk" - 修改完用
write()写入临时文件,再原子替换原文件 - 别跳过
read()的返回值检查——如果某 ini 文件语法有误,read()会静默跳过,导致备份了坏文件却没提示
最常被忽略的一点:备份不是目的,可验证的备份才是。每次替换后,建议用 filecmp.cmp() 校验备份与原文件是否字节一致——尤其当文件含 BOM 或混合编码时,肉眼难辨差异。


















