You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用Python shutil.move移动文件时丢失文件的技术咨询

我来帮你拆解问题,先逐个解答你的疑问,再分析你代码里藏着的坑,最后给你测试和修正方案:

1. shutil.move() 会把文件移去临时文件夹吗?

不会。shutil.move() 的设计就是直接把文件/目录从你指定的源路径转移到目标路径,不会默认用到临时文件夹。只有当源和目标在不同文件系统(比如从本地磁盘移到网络共享盘)时,它会先复制文件到目标,再删除源文件,但全程都是指向你设定的目标路径,不会绕去临时目录。

2. shutil.move() 会删除源文件吗?

这正是它的核心功能:

  • 如果源和目标在同一个文件系统下,它会执行重命名操作(和系统的mv命令一样),源文件会直接从原位置消失,出现在目标路径。
  • 如果跨文件系统,它会先复制文件到目标,然后删除源文件
  • 注意:如果移动过程中出现权限不足、目标路径不可写这类错误,可能会留下半完成的文件,但只要复制/重命名成功,源文件一定会被移除。

3. 怎么测试脚本找出文件丢失的原因?

结合你的代码情况,推荐这几个测试步骤:

  • 加日志打印:在移动文件前,打印源路径和目标路径,确认路径是否符合你的预期。比如加一行:
    print(f"准备移动: {os.path.join(path, rawfiles)} -> {os.path.join(desination, rawfiles)}")
    
  • 先用copy代替move测试:把shutil.move()换成shutil.copy(),这样即使出错,源文件还在,方便你排查路径是否正确。
  • 单文件测试:先挑一个文件单独处理,注释掉批量循环的逻辑,验证单个文件能不能准确移到你想要的目录。
  • 检查路径和权限:确认目标路径的拼写(比如你代码里变量名写的desination是笔误,但路径字符串本身是对的?仔细核对dropbox + "/"+ samples + "/raw/"是不是你要的路径),同时确保脚本对源目录和目标目录有读写权限。

你的代码里的关键问题

仔细看你的filemover函数,发现一个严重的循环冗余问题:

for samples in ID:
    for fs in files:
        if samples in fs:
            # 创建目标目录
            for rawfiles in fnmatch.filter(files, pat="*"):  # 这里遍历所有文件
                if samples in rawfiles:
                    shutil.move(...)

当某个samples匹配到第一个fs时,内层的fnmatch循环会把所有匹配该samples的文件全部移走。但外层的for fs in files还会继续跑,当后续的fs也匹配这个samples时,再次进入内层循环,此时源文件已经被移走了,就会抛出“文件不存在”的错误。但其实文件已经成功移动到目标目录了,只是后续重复循环导致报错。

另外,fnmatch.filter(files, pat="*")完全没必要,因为files已经是你筛选好的以"SSE"开头的文件列表,直接遍历files就行。


修正后的代码建议

import os
import shutil
import pandas as pd

path = '/path/to/source'
dropbox = '/path/to/dropbox'

# 获取所有以SSE开头的文件名(不带路径)
files = [f for f in os.listdir(path) if f.startswith("SSE")]

# 提取唯一的样本ID
sam_lis = [sam.split('_')[5] for sam in files]
sam_lis = pd.unique(sam_lis).tolist()

def filemover(sample_ids, file_list, target_root):
    """将文件移动到按样本ID创建的目标目录"""
    for sample_id in sample_ids:
        # 用os.path.join拼接路径,避免手动拼字符串的分隔符问题
        dest_dir = os.path.join(target_root, sample_id, 'raw')
        # 自动创建目录(包括父目录),无需手动判断是否存在
        os.makedirs(dest_dir, exist_ok=True)
        
        # 遍历文件列表,移动匹配当前样本ID的文件
        for filename in file_list:
            if sample_id in filename:
                src_path = os.path.join(path, filename)
                dest_path = os.path.join(dest_dir, filename)
                # 打印日志跟踪移动过程
                print(f"移动文件: {src_path} -> {dest_path}")
                # 先检查源文件是否存在,避免重复移动报错
                if os.path.exists(src_path):
                    shutil.move(src_path, dest_path)
                else:
                    print(f"警告:源文件已不存在,跳过: {src_path}")

# 调用函数执行移动
filemover(sam_lis, files, dropbox)

修正点说明:

  1. os.path.join()拼接路径,避免了手动写/导致的跨系统兼容问题(比如Windows用\)。
  2. os.makedirs(dest_dir, exist_ok=True)替代手动判断目录是否存在,代码更简洁,还能自动创建父目录。
  3. 移除了冗余的嵌套循环,每个样本ID只遍历一次文件列表,避免重复移动文件。
  4. 添加了源文件存在性检查,防止重复移动导致的“文件不存在”错误。
  5. 增加了日志打印,方便你跟踪每个文件的移动情况,出问题时能快速定位。

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

火山引擎 最新活动