应使用shutil.copyfileobj()手动分块复制大文件,以二进制模式打开文件并显式指定length参数(如1MB),避免内存爆满;它默认64KB缓冲,不处理编码,只做字节流搬运,适合任意文件类型。

因为 shutil 的底层实现(尤其是 shutil.copyfileobj())直接调用系统级缓冲和分块读写逻辑,避免了手动实现时常见的内存爆满、IO阻塞或元数据丢失问题。
大文件复制时内存占用飙升?用 shutil.copyfileobj() 控制块大小
手动用 open() + read() 读取一个 2GB 文件,若不指定 size,默认可能加载全部内容到内存——Python 进程瞬间吃掉 2GB RAM,还容易触发 OOM。而 shutil.copyfileobj() 默认使用 64KB 缓冲,且允许你显式控制:length=1024*1024(1MB 块)是更稳妥的常见选择。
- 必须传入二进制模式打开的文件对象(
"rb"和"wb"),文本模式会报错 - 不处理编码、换行符转换,只做字节流搬运,适合任意类型文件(视频、数据库 dump、tar 包等)
- 它不校验内容一致性,复制后需自行比对
hashlib.md5()或用shutil.disk_usage()验证空间是否匹配
跨文件系统移动失败?shutil.move() 自动降级为“复制+删除”
手动用 os.rename() 移动大文件时,一旦源和目标不在同一挂载点(比如从 /home 到 /mnt/usb),会直接抛出 OSError: [Errno 18] Invalid cross-device link。而 shutil.move() 内部捕获该错误,并自动切换成 shutil.copy2() + os.unlink() 流程——这对大文件意味着:先分块复制,再删源,全程可控。
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
- 复制阶段保留元数据(时间戳、权限),但删除源前不校验目标完整性,失败可能导致“两头丢”
- 如果目标磁盘空间不足,错误发生在复制中途,源文件仍存在;需配合
shutil.disk_usage()提前检查可用空间 - 不要在信号中断(如 Ctrl+C)时依赖
shutil.move()的原子性——它不是原子操作
需要保留创建时间、访问时间?shutil.copy2() 比 shutil.copy() 多一步 copystat()
很多场景(如备份日志、合规归档)要求目标文件的 st_atime(最后访问时间)、st_mtime(最后修改时间)与源一致。shutil.copy() 只复制内容和权限位,而 shutil.copy2() 在复制后额外调用 shutil.copystat(),把 stat 结构里的时间戳、inode 标志等一并搬过去。
立即学习“Python免费学习笔记(深入)”;
- Windows 上
st_ctime是创建时间,copystat()能保留;Linux 上它是 inode 创建时间,无法真正“设置”,所以实际效果有限 - 若目标文件系统不支持某些时间精度(如 FAT32 只精确到 2 秒),
copystat()会静默截断,不会报错 - 遇到只读文件系统时,
copystat()可能失败,但不影响内容复制成功——错误被忽略,这点容易被误以为“没生效”
真正麻烦的不是函数选错,而是忘了检查目标路径是否存在、磁盘空间够不够、源文件是否被其他进程锁住——这些都不是 shutil 能替你兜底的。它只是把“怎么搬”做得足够稳,但“搬之前看一眼”还得你自己来。

















