Python - 移动和覆盖文件和文件夹

问题描述 投票:0回答:7

我有一个目录“Dst Directory”,其中包含文件和文件夹,我有一个“src Directory”,其中也包含文件和文件夹。我想要做的是将“src 目录”的内容移动到“Dst 目录”并覆盖任何存在的同名文件。因此,例如“Src Directory ile.txt”需要移动到“Dst Directory\”并覆盖现有的 file.txt。这同样适用于某些文件夹,移动文件夹并将内容与“dst 目录”中的同一文件夹合并

我目前正在使用

shutil.move
将 src 的内容移动到 dst,但如果文件已经存在,则不会执行此操作,并且不会合并文件夹;它只会将该文件夹放入现有文件夹中。

更新:为了让事情更清楚一些,我正在做的是将存档解压缩到 Dst 目录,然后将 Src 目录的内容移动到那里并重新压缩,从而有效地更新 zip 存档中的文件。添加新文件或文件的新版本等时将重复此操作,这就是为什么需要覆盖和合并

python file move overwrite
7个回答
74
投票

这将遍历源目录,创建目标目录中尚不存在的任何目录,并将文件从源目录移动到目标目录:

import os
import shutil

root_src_dir = 'Src Directory\\'
root_dst_dir = 'Dst Directory\\'

for src_dir, dirs, files in os.walk(root_src_dir):
    dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
    if not os.path.exists(dst_dir):
        os.makedirs(dst_dir)
    for file_ in files:
        src_file = os.path.join(src_dir, file_)
        dst_file = os.path.join(dst_dir, file_)
        if os.path.exists(dst_file):
            # in case of the src and dst are the same file
            if os.path.samefile(src_file, dst_file):
                continue
            os.remove(dst_file)
        shutil.move(src_file, dst_dir)

任何预先存在的文件将首先被删除(通过

os.remove
),然后被相应的源文件替换。目标中已存在但源中不存在的任何文件或目录将保持不变。


67
投票

使用

copy()
代替,它愿意覆盖目标文件。如果您希望第一棵树消失,只需在完成迭代后单独
rmtree()
即可。

http://docs.python.org/library/shutil.html#shutil.copy

http://docs.python.org/library/shutil.html#shutil.rmtree

更新:

在源树上执行

os.walk()
。对于每个目录,检查它是否存在于目标端,如果丢失则
os.makedirs()
。对于每个文件,只需
shutil.copy()
,文件就会被创建或覆盖,以合适的为准。


10
投票

由于上述方法都不适合我,所以我编写了自己的递归函数。调用函数 copyTree(dir1, dir2) 合并目录。在 Linux 和 Windows 多平台上运行。

def forceMergeFlatDir(srcDir, dstDir):
    if not os.path.exists(dstDir):
        os.makedirs(dstDir)
    for item in os.listdir(srcDir):
        srcFile = os.path.join(srcDir, item)
        dstFile = os.path.join(dstDir, item)
        forceCopyFile(srcFile, dstFile)

def forceCopyFile (sfile, dfile):
    if os.path.isfile(sfile):
        shutil.copy2(sfile, dfile)

def isAFlatDir(sDir):
    for item in os.listdir(sDir):
        sItem = os.path.join(sDir, item)
        if os.path.isdir(sItem):
            return False
    return True


def copyTree(src, dst):
    for item in os.listdir(src):
        s = os.path.join(src, item)
        d = os.path.join(dst, item)
        if os.path.isfile(s):
            if not os.path.exists(dst):
                os.makedirs(dst)
            forceCopyFile(s,d)
        if os.path.isdir(s):
            isRecursive = not isAFlatDir(s)
            if isRecursive:
                copyTree(s, d)
            else:
                forceMergeFlatDir(s, d)

7
投票

您可以使用它来复制目录覆盖现有文件:

import shutil
shutil.copytree("src", "dst", dirs_exist_ok=True)

dirs_exist_ok
参数是在 Python 3.8 中添加的。

参见文档:https://docs.python.org/3/library/shutil.html#shutil.copytree


6
投票

如果您还需要使用只读标志覆盖文件,请使用以下命令:

def copyDirTree(root_src_dir,root_dst_dir):
"""
Copy directory tree. Overwrites also read only files.
:param root_src_dir: source directory
:param root_dst_dir:  destination directory
"""
for src_dir, dirs, files in os.walk(root_src_dir):
    dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
    if not os.path.exists(dst_dir):
        os.makedirs(dst_dir)
    for file_ in files:
        src_file = os.path.join(src_dir, file_)
        dst_file = os.path.join(dst_dir, file_)
        if os.path.exists(dst_file):
            try:
                os.remove(dst_file)
            except PermissionError as exc:
                os.chmod(dst_file, stat.S_IWUSR)
                os.remove(dst_file)

        shutil.copy(src_file, dst_dir)

1
投票

查看:

os.remove
删除现有文件。


0
投票

我也有类似的问题。我想移动文件和文件夹结构并覆盖现有文件,但不删除目标文件夹结构中的任何内容。

我通过使用

os.walk()
,递归调用我的函数并在我想要覆盖的文件和不存在的文件夹上使用
shutil.move()
解决了这个问题。

它的工作原理类似于

shutil.move()
,但好处是现有文件只会被覆盖,而不会被删除。

import os
import shutil

def moverecursively(source_folder, destination_folder):
    basename = os.path.basename(source_folder)
    dest_dir = os.path.join(destination_folder, basename)
    if not os.path.exists(dest_dir):
        shutil.move(source_folder, destination_folder)
    else:
        dst_path = os.path.join(destination_folder, basename)
        for root, dirs, files in os.walk(source_folder):
            for item in files:
                src_path = os.path.join(root, item)
                if os.path.exists(dst_file):
                    os.remove(dst_file)
                shutil.move(src_path, dst_path)
            for item in dirs:
                src_path = os.path.join(root, item)
                moverecursively(src_path, dst_path)
© www.soinside.com 2019 - 2024. All rights reserved.