shutil移动文件保持相同目录结构

5 投票
2 回答
10231 浏览
提问于 2025-04-16 15:01

我想移动很多文件,这些文件的路径保存在一个列表里。我想保留整个文件夹的结构,但想把它们移动到另一个文件夹。

比如说,这些文件的路径是:
D:\test\test1\test1.txt
D:\test\test1\test2.txt

我想把它们从 D:\ 移动到 C:\,同时保持文件夹的结构。我该怎么做呢?

这是我写的代码,但它不管用:

import os, fnmatch
import shutil


f=open('test_logs.txt','r') #logs where filenames are stored with filenames as first entry

for line in f:
    filename=line.split()
    output_file="C:" + filename[0].lstrip("D:")
    shutil.move(filename[0],output_file)

我可以正确读取文件名,也能生成目标文件名,但当我运行代码时,它给我报错,说“没有这样的文件或目录”(并且显示了输出文件名的路径)。

2 个回答

2

更新: 噢,我明白问题了 -- shutil.move 不能把文件移动到一个不存在的目录。要实现你想做的事情,首先得创建好新的目录结构。使用内置的移动功能比自己写复制和删除的过程要安全一些,所以你可以这样做:

with open('test_logs.txt','r') as f:
    files_to_copy = [line.split()[0] for line in f]
paths_to_copy = set(os.path.split(filename)[0] for filename in files_to_copy)

def ignore_files(path, names, ptc=paths_to_copy):
    return [name for name in names if os.path.join(path, name) not in ptc]

shutil.copytree(src, dst, ignore=ignore_files)

for filename in files_to_copy:
    output_file="C:" + filename.lstrip("D:")
    shutil.move(filename, output_file)

如果这样不行,告诉我一声。


原帖: 如果你只想移动部分文件,最好的办法是使用 shutil.copytreeignore 关键字。假设你的文件列表包含完整的路径和目录(比如 ['D:\test\test1\test1.txt', 'D:\test\test1\test2.txt', 'D:\test\test1']),你可以创建一个 ignore_files 函数,然后这样使用:

files_to_copy = ['D:\test\test1\test1.txt', 'D:\test\test1\test2.txt', 'D:\test\test1']

def ignore_files(path, names, ftc=files_to_copy):
    return [name for name in names if os.path.join(path, name) not in ftc]

shutil.copytree(src, dst, ignore=ignore_files)

然后你可以直接删除 files_to_copy 中的文件:

for f in files_to_copy:
    try:
        os.remove(f)
    except OSError:  # can't remove() a directory, so pass
        pass 

我测试过这个 -- 确保你在 files_to_copy 中包含你想复制的路径和文件 -- 否则,这样会在没有复制的情况下删除文件。

5

我觉得你想要的东西大概是这样的:

import sys
import os
import shutil

# terminology:
# path = full path to a file, i.e. directory + file name
# directory = directory, possibly starting with a drive
# file name = the last component of the path

sourcedrive = 'D:'
destdrive = 'C:'

log_list_file = open('test_logs.txt', 'r')
for line in log_list_file:
    sourcepath = line.split()[0]  # XXX is this correct?
    if sourcepath.startswith(sourcedrive):
        destpath = sourcepath.replace(sourcedrive, destdrive, 1)
    else:
        print >>sys.stderr, 'Skipping %s: Not on %s' % (sourcepath, sourcedrive)
        continue

    destdir = os.path.dirname(destpath)    

    if not os.path.isdir(destdir):
        try:
            os.makedirs(destdir)
        except (OSError, IOError, Error) as e:
            print >>sys.stderr, 'Error making %s: %s' % (destdir, e)
            continue

    try:
        shutil.move(sourcepath, destpath)
    except (OSError, IOError, Error) as e:
        print >>sys.stderr, 'Error moving %s to %s: %s' % (sourcepath, destpath, e)

你还想在源目录为空的时候把它删除吗?

撰写回答