最轻量可控的备份方式是shutil.copytree()配合strftime()生成下划线分隔时间戳目录名(如backup_2024-05-21_14-37-22),保留完整目录结构、属性和符号链接,支持忽略规则与父目录自动创建,避免打包带来的恢复低效与兼容性问题。

直接用 shutil.copytree() 配合 datetime.strftime() 生成带时间戳的备份目录,是最轻量、最可控的方式——不需要额外依赖,不碰系统命令,也不用处理压缩包的边界情况。
为什么不用 shutil.make_archive()?
它默认打包成 zip/tar,但多数备份场景要的是「可直接浏览、快速恢复」的完整文件夹结构。一旦打包,单个文件修复就得解压→改→重压,效率低;而且 zip 在 Windows 上可能因路径长度或权限丢失元数据(如修改时间)。shutil.copytree() 原样复制,保留目录树、文件属性和符号链接(加 symlinks=True 即可)。
- Windows 下若源路径含中文或空格,
shutil.make_archive()有时会静默失败,而copytree()更稳定 - 目标路径已存在时,
copytree()默认报FileExistsError,正好防止误覆盖;make_archive()则可能静默覆盖同名压缩包 - 想跳过某些子目录(比如
__pycache__或.git),copytree()支持ignore参数,make_archive()不支持精细过滤
如何生成安全、可排序的备份目录名?
别用 datetime.now().isoformat()(含冒号,Windows 不允许),也别用 strftime('%Y-%m-%d %H:%M')(空格在 shell 中易出问题)。统一用下划线分隔的紧凑格式:
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
backup_2024-05-21_14-37-22
这样既保证字典序 = 时间序(ls backup_* 自然按时间排列),又兼容所有操作系统路径规则。
- 推荐写法:
datetime.now().strftime('backup_%Y-%m-%d_%H-%M-%S') - 如果希望每天只一个备份目录(避免太多碎片),可用
'backup_%Y-%m-%d',但需手动检查当天是否已存在 - 注意:
%f(微秒)没必要,且会导致目录名过长;%Z或%z可能引入非 ASCII 字符,应避免
实际备份脚本的关键细节
核心是三步:构造目标路径 → 确保父目录存在 → 复制。中间必须处理两个现实问题:目标已存在、忽略临时文件。
- 用
os.path.exists()检查目标目录前,先用os.makedirs(backup_root, exist_ok=True)创建上级目录(比如backups/),否则copytree()会因父目录不存在而失败 - 忽略规则建议封装为函数,例如跳过
.git、__pycache__、*.pyc:def ignore_func(dir, files):<br> return [f for f in files if f in ('.git', '__pycache__') or f.endswith('.pyc')]然后传给shutil.copytree(src, dst, ignore=ignore_func) - 若源目录很大,
copytree()是同步阻塞操作,没有进度反馈。如需感知进度,得自己遍历 +shutil.copy2(),但绝大多数本地备份无需这么复杂
真正容易被忽略的是权限与硬链接:Linux/macOS 上,copytree() 默认不复制文件所有权(只保留模式位),且会把硬链接展开为独立副本。如果备份的是开发环境或需要精确还原的配置,得额外考虑 shutil.copytree(..., copy_function=shutil.copy2) 并接受硬链接丢失——这是权衡,不是 bug。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










