You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

shutil.copy()重复调用时抛出无效参数错误排查

WSL2下使用shutil.copy循环拷贝时第二次报错Errno 22的问题解决

问题描述

我在通过WSL2向挂载的Azure存储(含blobfuse、SMB文件共享、NFSv3、RClone)拷贝文件时遇到异常:使用带装饰器的copy函数循环执行性能测试时,第一次拷贝正常,第二次直接抛出OSError: [Errno 22] Invalid argument,但直接调用shutil.copy指定相同路径却能正常运行。

核心代码

装饰器与拷贝函数:

def time_and_log(func):
    def inner_function(*args,**kwargs):
        times = np.array([])
        repititions = kwargs.pop("repititions",1)
        for i in range(repititions):
            print(f"i: {i}")
            start_time = time.perf_counter()
            logfile = func(*args,**kwargs)
            end_time = time.perf_counter()
            elapsed_time = end_time - start_time
            times = np.append(times,elapsed_time)
            # 省略日志记录逻辑
    return inner_function

@time_and_log
def copy(src,dst,logfile,repititions=1):
    if Path(src).is_dir():
        shutil.copytree(src,dst)
    else:
        if os.path.isfile(dst):
            os.remove(dst)
        shutil.copy(src,dst)
    return logfile

复现代码:

LOG_FILE = "log.txt"
REPS = 5
dst = r"\\wsl.localhost\\Ubuntu\\home\\me\\mountpoint\\"
src_path = ".\\anypath\\"
test_file = "myfile.bin"

copy(src=src_path+test_file,dst=dst+test_file,logfile=LOG_FILE,repititions=REPS)

可能原因分析

  1. 跨环境路径解析冲突:使用Windows风格的\\wsl.localhost\\...路径在WSL内部Python环境中,第一次操作后挂载文件系统对路径的缓存或解析逻辑出现异常,导致第二次路径识别失败。
  2. 挂载文件系统同步延迟:Azure类存储挂载(如blobfuse、SMB)存在状态同步延迟,第一次删除文件后,挂载层未及时更新文件状态,第二次写入时因状态不一致触发错误。
  3. 文件句柄残留:os.remove(dst)删除文件后,挂载系统可能仍保留文件句柄,导致shutil.copy无法创建新文件。

解决办法

1. 改用WSL原生路径

替换Windows风格路径为WSL内部路径,避免跨环境解析问题:

# 替换复现代码中的dst定义
dst = "/home/me/mountpoint/"

2. 增加删除后的同步延迟

在删除文件后增加短暂等待,给挂载系统足够时间同步状态:

# 修改copy函数的else块
else:
    if os.path.isfile(dst):
        os.remove(dst)
        time.sleep(0.5)  # 根据挂载类型调整时长,SMB/blobfuse可适当延长
    shutil.copy(src, dst)

3. 替换为覆盖写入逻辑

跳过删除操作,直接用文件流覆盖写入,避免删除带来的同步问题:

# 修改copy函数的else块
else:
    with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
        shutil.copyfileobj(fsrc, fdst)

4. 修复装饰器参数逻辑

移除被装饰函数中冗余的repititions参数,避免参数传递混淆:

@time_and_log
def copy(src,dst,logfile):  # 去掉repititions=1参数
    if Path(src).is_dir():
        shutil.copytree(src,dst)
    else:
        if os.path.isfile(dst):
            os.remove(dst)
        shutil.copy(src,dst)
    return logfile

验证建议

优先尝试改用WSL原生路径,这是解决跨环境路径问题最直接的方案;若仍有异常,再依次测试增加延迟或替换写入逻辑的方案。

内容的提问来源于stack exchange,提问作者Jamalan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 17:06:49