Python中shutil.copy报Errno13权限拒绝但shutil.move运行正常问题解析
报错根源解析
- 你遇到的
PermissionError并非系统层面的目录访问权限不足,核心原因是shutil模块下两个函数的设计适用场景存在本质差异,无法直接互换参数使用。 shutil.move()支持传入文件、文件夹两类路径作为源对象:函数内部会先判断源路径的类型,如果是文件夹就走专门的目录迁移逻辑,不会尝试把目录本身当二进制文件读取,因此传入C:\Documents\Input这类目录路径可以正常运行。shutil.copy()仅支持传入单个文件作为源对象,不具备目录递归遍历能力:从错误堆栈可以看到,传入目录路径后函数直接进入了copyfile()的处理分支,该分支会执行open(src, 'rb')逻辑——尝试把C:\Documents\Input这个文件夹本身按二进制文件打开。Windows系统本身禁止将目录路径作为普通文件打开,因此直接抛出权限拒绝错误。- 哪怕给Python授予最高级别的管理员权限,这种把目录当文件打开的操作依然会报同样的错误,和系统权限配置无关。
适配需求的解决方案
你的需求是“把Input目录下的所有文件、文件夹结构完整复制到Output,同时保留源路径内容”,可以根据场景选择以下实现方式:
- 方案1:使用Python内置的目录递归复制工具
shutil.copytree(),和shutil.move()的目录处理逻辑对齐,是最简洁的实现。
需要注意shutil.copytree()在Python3.8及以上版本支持dirs_exist_ok参数,允许目标Output目录提前存在,不会触发FileExistsError。参考代码:import shutil input_path = r'C:\Documents\Input' output_path = r'C:\Documents\Output' shutil.copytree( src=input_path, dst=output_path, dirs_exist_ok=True )路径结构注意:
shutil.copytree()和shutil.move()的路径拼接逻辑存在差异,避免预期错位:- 若你之前运行
shutil.move(input_path, output_path)时,因为output_path是已存在的目录,最终文件会被移动到C:\Documents\Output\Input\路径下(也就是把Input整个文件夹作为子项放到Output目录里)。 - 如果用上述copytree代码,会把Input目录内部的所有内容直接复制到Output根目录下,不会生成嵌套的Input子文件夹。
如果你的预期是和move生成的目录结构完全一致,只需要把copytree的dst参数修改为os.path.join(output_path, "Input")即可。
- 若你之前运行
- 方案2:如果需要对复制过程加自定义逻辑(比如跳过特定类型文件、过滤临时目录),可以手动遍历源目录结构,逐个完成目录创建、文件复制。参考实现:
import os import shutil input_path = r'C:\Documents\Input' output_path = r'C:\Documents\Output' for root, _, files in os.walk(input_path): # 计算源路径下的相对层级,保证复制后的目录结构和源目录完全一致 relative_level = os.path.relpath(root, input_path) current_target_dir = os.path.join(output_path, relative_level) os.makedirs(current_target_dir, exist_ok=True) # 逐文件复制,copy2会保留文件的修改时间、权限等元数据,和move的迁移效果一致 for file_name in files: source_file = os.path.join(root, file_name) target_file = os.path.join(current_target_dir, file_name) shutil.copy2(source_file, target_file)
内容的提问来源于stack exchange,提问作者llamallama101092030
相关产品推荐
相关产品推荐

