【问题标题】:Python - Move and overwrite files and foldersPython - 移动和覆盖文件和文件夹
【发布时间】:2011-11-17 04:38:19
【问题描述】:

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

我目前正在使用 shutil.move 将 src 的内容移动到 dst 但如果文件已经存在并且不会合并文件夹,它将不会这样做;它只会将文件夹放在现有文件夹中。

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

已解决:我通过使用 distutils.dir_util.copy_tree(src, dst) 解决了我的问题,这会将文件夹和文件从 src 目录复制到 dst 目录,并在必要时覆盖/合并。希望对一些人有所帮助!

希望这是有道理的, 谢谢!

【问题讨论】:

标签: python file move overwrite


【解决方案1】:

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

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)。目标中已存在但源中不存在的任何文件或目录都将保持不变。

【讨论】:

  • 太好了,谢谢!我认为这就是 Brandon Craig Rhodes 所说的,但感谢您提供 sn-p!不幸的是,你不能有两个正确的答案^^
  • 复制它们就像用“shutil.copy”替换“shutil.move”一样简单。
  • 如果 root_dst_dir == 'dir1\\dir2\\',os.mkdir(dst_dir) 会抛出一个错误,提示“没有这样的文件或目录:'dir1\\dir2\\'”。使用 os.makedirs(dst_dir) 可以避免这个问题。
  • 我已经编辑了答案以包含@lyen 和我自己指出的修复。这个解决方案对我来说效果很好。谢谢!
  • 如何删除root_src_dir中的空目录?使用 rmdir 时出现 Errorno 16
【解决方案2】:

改用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() 即可创建或覆盖该文件,视情况而定。

【讨论】:

  • copy() 不能复制文件夹,可以吗?
  • 否,但每个文件上的move() 也不会创建目标目录,所以我假设您的代码已经对不存在的目标文件夹执行了os.makedirs()。啊!我想我现在明白了——你是同时在整个树上做move()?戈奇亚。将更新我的答案。
  • 感谢您的更新,问题在于要复制的文件总是在变化(添加了新文件等),所以每次添加新文件以进行移动时,我都必须更新代码,如果你明白的话。无论如何,我使用 distutils.dir_util.copy_tree(src, dst) 管理它,它复制文件夹和文件并在需要时覆盖/合并,感谢您的帮助
  • os.walk() 每次运行时都会为您提供源文件的新列表,因此如果我理解您的问题,如果列表每次都更改也没关系。但是,祝你好运 distutils 解决方案——当有人依赖 distutils 而不是标准库时,这总是一种冒险!不过,我怀疑他们会保持该功能正常工作。
  • 哦,我明白了,我并没有真正理解 os.walk 方法,我以为您必须定义要使用 shutil.copy 复制的文件。我现在明白了,很久没有使用 os.walk 了。我会正确回答这个问题,因为我可以看到它有效,但由于简单,我现在会坚持使用 distutils
【解决方案3】:

由于上述方法都不适合我,所以我编写了自己的递归函数。调用函数 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)

【讨论】:

  • 使用其他答案时,哪些场景不适合您?
  • 值得注意的是,如果 src 有一个与 dst 中的目录同名的文件,此解决方案会将文件放在共享其名称的目录中,而 Ray Vega's solution 将抛出 OSError: [Errno 21] Is a directory
  • 这很完美。没有 OSError 10/12/16/21 ...我在尝试 sys.move() 时遇到了很多错误。谢谢。
【解决方案4】:

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

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)

【讨论】:

    【解决方案5】:

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

    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】:

      查看:os.remove 以删除现有文件。

      【讨论】:

      • 问题是我要添加到文件夹中的文件会改变(将添加新文件并更新旧文件),所以我无法列出要删除的内容,谢谢虽然
      【解决方案7】:

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

      我通过使用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)
      

      【讨论】:

      • 您的代码不起作用,dst_file 根本没有定义。
      猜你喜欢
      • 2013-11-27
      • 2012-02-05
      • 1970-01-01
      • 2015-12-12
      • 2022-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-09
      相关资源
      最近更新 更多