shutil不适合实时监控或原子化事务,核心价值是跨平台批量处理;dirs_exist_ok=True不覆盖仅跳过检查,真正覆盖需先rmtree再copytree;move跨设备失败主因是磁盘空间或挂载异常;make_archive压缩包多父目录因base_dir传入绝对路径所致。

shutil 不适合实时监控或原子化事务操作,它本质是 os 模块的封装增强,核心价值在跨平台批量处理——别把它当 rsync 用,也别指望它自动解决权限冲突。
复制整个目录时,shutil.copytree() 的 dirs_exist_ok 参数到底要不要开?
Python 3.8+ 才有 dirs_exist_ok 参数,默认为 False,意味着目标目录存在就直接报 FileExistsError。很多用户误以为开了就能“覆盖”,其实它只跳过“目标路径已存在”的检查,不删除旧内容,也不合并——结果是新文件写入、旧文件残留,形成脏数据。
- 要真正覆盖:先
shutil.rmtree(target_dir),再shutil.copytree(src, target, dirs_exist_ok=False) - 要增量同步(类似 rsync):不用
copytree,改用shutil.copy2()配合os.walk()自行遍历比对 - 若目标目录结构复杂且需保留部分旧配置,
dirs_exist_ok=True+ 手动清理无关子目录更安全
移动大文件时 shutil.move() 突然卡住或失败,怎么定位?
shutil.move() 在同文件系统内是 os.rename()(毫秒级),跨文件系统则退化为“复制 + 删除”,此时失败往往不是代码问题,而是磁盘空间、权限或挂载状态异常。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 检查源和目标是否在同一挂载点:
os.stat(src).st_dev == os.stat(dst).st_dev - 跨设备移动前,用
shutil.disk_usage(dst_root)验证剩余空间是否 ≥ 源文件大小 - 若目标路径含中文或特殊符号,确保终端和 Python 运行环境编码一致(常见于 Windows cmd 下默认 gbk 导致
OSError: [Errno 22]) - 不要在
move()后立刻os.listdir()判断成功——删除动作可能延迟,建议用os.path.exists(src)和os.path.exists(dst)双检
用 shutil.make_archive() 打包时,为什么压缩包里多了父目录?
这是路径传参方式导致的典型误解。root_dir 是归档时的“工作根”,base_dir 是要打包的相对起点。如果 base_dir="project/src" 且 root_dir="/home/user",那么压缩包内路径就是 project/src/xxx.py;但如果误把绝对路径当 base_dir(如 base_dir="/home/user/project/src"),make_archive 会按 root_dir="/" 解析,结果打出 home/user/project/src/...。
立即学习“Python免费学习笔记(深入)”;
- 始终用相对路径传
base_dir,并显式指定root_dir为其父目录 - 调试时加
dry_run=True(需自行 patch 或用zipfile模拟),或打完包立即zipfile.ZipFile(archive).namelist()[:3]查看前几项 - 需要排除某些文件(如
.pyc):不用make_archive,改用shutil.register_archive_format()+ 自定义函数,或直接上tarfile/zipfile
最常被忽略的是 shutil.copy2() 的元数据行为:它复制 atime/mtime,但不保证 ctime(创建时间)可移植,且在某些文件系统(如 FAT32)上会静默丢弃。如果你依赖时间戳做增量判断,得自己用 os.stat().st_mtime 显式保存校验值。

















