shutil.move报错文件夹被占用但文件均成功转移的排查咨询
问题排查与解决方法
1. 确认占用进程
- 直接通过Windows自带工具实锤占用来源:按下
Win+R输入resmon打开资源监视器,切换到「CPU」标签,在「关联的句柄」搜索框输入报错的文件夹路径C:\Users\Ze\PycharmProjects\Ploutos\ProductList\Unedited\1005001769427465\Images,即可看到持有句柄的进程,确认是否为Pycharm的索引进程(通常为pycharm64.exe或对应的索引子进程)。 - 如果确认是Pycharm索引导致的占用,将
ProductList目录加入Pycharm排除列表即可解决:打开设置>项目>项目结构,找到对应目录右键标记为「排除」,Pycharm将不再对该目录做实时索引,也就不会持有文件夹句柄。
2. 排查代码自身的隐性占用
你提到已卸载所有资源,大概率存在遗漏的资源持有场景:
- 检查所有操作过
Images目录下文件的代码,是否存在open()打开文件后未手动关闭、PIL/OpenCV等图片处理库操作完文件后未正确释放资源的情况,哪怕是只读模式打开文件也会触发占用锁,建议所有文件操作都使用with上下文管理器,自动释放句柄避免遗漏。 - 检查是否有代码将当前工作目录切换到了待移动的子目录下未切回,进程的当前工作目录本身也会触发占用锁。
3. 偶发占用的兼容方案
如果是Pycharm索引、Windows Defender扫描这类第三方进程的临时占用,加重试机制即可解决绝大多数偶发报错,同时优化路径拼接逻辑避免手动写反斜杠的兼容问题:
import time import shutil import os def move_product_to_edited(product_id, max_retries=3, retry_interval=1): global products_edited_during_session_counter unedited_products_path = os.path.join(application_path, 'ProductList', 'Unedited') edited_products_path = os.path.join(application_path, 'ProductList', 'Edited') src_path = os.path.join(unedited_products_path, str(product_id)) dst_path = os.path.join(edited_products_path, str(product_id)) if not os.path.exists(src_path): return for retry in range(max_retries): try: shutil.move(src_path, dst_path) break except PermissionError: if retry == max_retries - 1: # 重试耗尽后再抛出错误 raise time.sleep(retry_interval)
4. 进阶排查方案
如果上述方法都未定位到问题:
- 使用Process Explorer工具的查找句柄功能,比系统自带资源监视器展示的信息更详细,可以定位到具体持有句柄的线程,甚至对应调用栈。
- 可以在执行
shutil.move前加1秒延迟测试,如果加延迟后不再报错,基本可以确定是第三方进程的临时占用,直接用重试方案即可无需额外排查。
内容的提问来源于stack exchange,提问作者José Guedes
相关产品推荐
相关产品推荐

