如何使用Python将整个文件目录复制到现有目录中?

如何使用Python将整个文件目录复制到现有目录中?,python,shutil,copytree,Python,Shutil,Copytree,从包含名为bar(包含一个或多个文件)的目录和名为baz(也包含一个或多个文件)的目录中运行以下代码。确保没有名为foo的目录 import shutil shutil.copytree('bar', 'foo') shutil.copytree('baz', 'foo') 它将在以下情况下失败: $ python copytree_test.py Traceback (most recent call last): File "copytree_test.py", line 5, in

从包含名为
bar
(包含一个或多个文件)的目录和名为
baz
(也包含一个或多个文件)的目录中运行以下代码。确保没有名为
foo
的目录

import shutil
shutil.copytree('bar', 'foo')
shutil.copytree('baz', 'foo')
它将在以下情况下失败:

$ python copytree_test.py 
Traceback (most recent call last):
  File "copytree_test.py", line 5, in <module>
    shutil.copytree('baz', 'foo')
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/shutil.py", line 110, in copytree
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/os.py", line 172, in makedirs
OSError: [Errno 17] File exists: 'foo'
我是否需要使用
shutil.copy()
baz
中的每个文件复制到
foo
?(在我已经用
shutil.copytree()
?)将“bar”的内容复制到“foo”之后)或者有更简单/更好的方法吗?

dst
命名的目标目录必须不存在;它将被创建,同时丢失父目录


我认为您最好的选择是
os.walk
第二个和所有后续目录、目录和文件,并对目录执行额外的
copystat
。毕竟,正如文档中所解释的那样,
copytree
正是这么做的。或者你可以
copy
copystat
每个目录/文件和
os.listdir
而不是
os.walk

我认为最快最简单的方法是让python调用系统命令

例如

import os
cmd = '<command line call>'
os.system(cmd)
导入操作系统
cmd=''
操作系统(cmd)
Tar和gzip将目录升级。。。。在所需位置解压并解压目录


是吗?

标准
shutil.copytree
的这一限制似乎是武断和恼人的。解决方法:

import os, shutil
def copytree(src, dst, symlinks=False, ignore=None):
    for item in os.listdir(src):
        s = os.path.join(src, item)
        d = os.path.join(dst, item)
        if os.path.isdir(s):
            shutil.copytree(s, d, symlinks, ignore)
        else:
            shutil.copy2(s, d)
请注意,它与标准的copytree不完全一致:

  • 它不支持
    src
    树的根目录的
    symlinks
    ignore
    参数
  • 对于
    src
    的根级别的错误,它不会引发
    shutil.Error
  • 如果复制子树时出错,它将为该子树引发
    shutil.Error
    ,而不是尝试复制其他子树并引发单个组合的
    shutil.Error

在atzz对函数的回答中,上述函数始终尝试将文件从源复制到目标,这一点略有改进

def copytree(src, dst, symlinks=False, ignore=None):
    if not os.path.exists(dst):
        os.makedirs(dst)
    for item in os.listdir(src):
        s = os.path.join(src, item)
        d = os.path.join(dst, item)
        if os.path.isdir(s):
            copytree(s, d, symlinks, ignore)
        else:
            if not os.path.exists(d) or os.stat(s).st_mtime - os.stat(d).st_mtime > 1:
                shutil.copy2(s, d)
在我上面的实现中

  • 创建输出目录(如果尚未存在)
  • 通过递归调用我自己的方法来复制目录
  • 当我们真正复制文件时,我只检查文件是否被修改 我们应该抄

我正在使用上述功能以及scons构建。这对我帮助很大,因为每次编译时,我可能不需要复制整个文件集。。但只有被修改的文件。

一个受atzz和Mital Vora启发的合并文件:

#!/usr/bin/python
import os
import shutil
import stat
def copytree(src, dst, symlinks = False, ignore = None):
  if not os.path.exists(dst):
    os.makedirs(dst)
    shutil.copystat(src, dst)
  lst = os.listdir(src)
  if ignore:
    excl = ignore(src, lst)
    lst = [x for x in lst if x not in excl]
  for item in lst:
    s = os.path.join(src, item)
    d = os.path.join(dst, item)
    if symlinks and os.path.islink(s):
      if os.path.lexists(d):
        os.remove(d)
      os.symlink(os.readlink(s), d)
      try:
        st = os.lstat(s)
        mode = stat.S_IMODE(st.st_mode)
        os.lchmod(d, mode)
      except:
        pass # lchmod not available
    elif os.path.isdir(s):
      copytree(s, d, symlinks, ignore)
    else:
      shutil.copy2(s, d)
  • 与shutil.copytree的行为相同,具有符号链接忽略参数
  • 如果不存在,则创建目录目标结构
  • 如果dst已存在,则不会失败

    • 这是我对同一任务的看法:

      import os, glob, shutil
      
      def make_dir(path):
          if not os.path.isdir(path):
              os.mkdir(path)
      
      
      def copy_dir(source_item, destination_item):
          if os.path.isdir(source_item):
              make_dir(destination_item)
              sub_items = glob.glob(source_item + '/*')
              for sub_item in sub_items:
                  copy_dir(sub_item, destination_item + '/' + sub_item.split('/')[-1])
          else:
              shutil.copy(source_item, destination_item)
      

      这是从atzz提供的原始最佳答案中得到的启发,我刚刚添加了替换文件/文件夹逻辑。因此它实际上不会合并,而是删除现有文件/文件夹并复制新文件/文件夹:

      import shutil
      import os
      def copytree(src, dst, symlinks=False, ignore=None):
          for item in os.listdir(src):
              s = os.path.join(src, item)
              d = os.path.join(dst, item)
              if os.path.exists(d):
                  try:
                      shutil.rmtree(d)
                  except Exception as e:
                      print e
                      os.unlink(d)
              if os.path.isdir(s):
                  shutil.copytree(s, d, symlinks, ignore)
              else:
                  shutil.copy2(s, d)
          #shutil.rmtree(src)
      

      取消对rmtree的注释,使其成为移动函数。

      以下是标准库的一部分解决方案:

      from distutils.dir_util import copy_tree
      copy_tree("/a/b/c", "/x/y/z")
      
      请看这个类似的问题

      • 参考-

        • 这是一个受此线程启发的版本,它更接近于模仿
          distutils.file\u util.copy\u file

          updateonly
          是一个bool,如果为True,则只复制修改日期比
          dst
          中现有文件更新的文件,除非
          forceupdate
          中列出,该文件将不考虑复制

          ignore
          forceupdate
          需要与
          src
          相关的文件名或文件夹/文件名列表,并接受类似于
          glob
          fnmatch
          的Unix样式通配符

          该函数返回已复制的文件列表(如果
          dryrun
          为True,则返回将被复制的文件列表)


          以前的解决方案存在一些问题,
          src
          可能会在没有任何通知或异常的情况下覆盖
          dst

          我添加了一个
          predict\u error
          方法来在复制之前预测错误。
          copytree
          主要基于Cyrille Pontvieux的版本

          使用
          predict\u error
          首先预测所有错误是最好的,除非您希望看到在执行
          copytree
          直到修复所有错误时一个接一个地引发异常

          def predict_error(src, dst):  
              if os.path.exists(dst):
                  src_isdir = os.path.isdir(src)
                  dst_isdir = os.path.isdir(dst)
                  if src_isdir and dst_isdir:
                      pass
                  elif src_isdir and not dst_isdir:
                      yield {dst:'src is dir but dst is file.'}
                  elif not src_isdir and dst_isdir:
                      yield {dst:'src is file but dst is dir.'}
                  else:
                      yield {dst:'already exists a file with same name in dst'}
          
              if os.path.isdir(src):
                  for item in os.listdir(src):
                      s = os.path.join(src, item)
                      d = os.path.join(dst, item)
                      for e in predict_error(s, d):
                          yield e
          
          
          def copytree(src, dst, symlinks=False, ignore=None, overwrite=False):
              '''
              would overwrite if src and dst are both file
              but would not use folder overwrite file, or viceverse
              '''
              if not overwrite:
                  errors = list(predict_error(src, dst))
                  if errors:
                      raise Exception('copy would overwrite some file, error detail:%s' % errors)
          
              if not os.path.exists(dst):
                  os.makedirs(dst)
                  shutil.copystat(src, dst)
              lst = os.listdir(src)
              if ignore:
                  excl = ignore(src, lst)
                  lst = [x for x in lst if x not in excl]
              for item in lst:
                  s = os.path.join(src, item)
                  d = os.path.join(dst, item)
                  if symlinks and os.path.islink(s):
                      if os.path.lexists(d):
                          os.remove(d)
                      os.symlink(os.readlink(s), d)
                      try:
                          st = os.lstat(s)
                          mode = stat.S_IMODE(st.st_mode)
                          os.lchmod(d, mode)
                      except:
                          pass  # lchmod not available
                  elif os.path.isdir(s):
                      copytree(s, d, symlinks, ignore)
                  else:
                      if not overwrite:
                          if os.path.exists(d):
                              continue
                      shutil.copy2(s, d)
          

          这是我对这个问题的看法。我修改了copytree的源代码以保留原始功能,但现在当目录已经存在时,不会发生错误。我还对它进行了更改,这样它就不会覆盖现有文件,而是保留了两个副本,一个带有修改过的名称,因为这对我的应用程序很重要

          import shutil
          import os
          
          
          def _copytree(src, dst, symlinks=False, ignore=None):
              """
              This is an improved version of shutil.copytree which allows writing to
              existing folders and does not overwrite existing files but instead appends
              a ~1 to the file name and adds it to the destination path.
              """
          
              names = os.listdir(src)
              if ignore is not None:
                  ignored_names = ignore(src, names)
              else:
                  ignored_names = set()
          
              if not os.path.exists(dst):
                  os.makedirs(dst)
                  shutil.copystat(src, dst)
              errors = []
              for name in names:
                  if name in ignored_names:
                      continue
                  srcname = os.path.join(src, name)
                  dstname = os.path.join(dst, name)
                  i = 1
                  while os.path.exists(dstname) and not os.path.isdir(dstname):
                      parts = name.split('.')
                      file_name = ''
                      file_extension = parts[-1]
                      # make a new file name inserting ~1 between name and extension
                      for j in range(len(parts)-1):
                          file_name += parts[j]
                          if j < len(parts)-2:
                              file_name += '.'
                      suffix = file_name + '~' + str(i) + '.' + file_extension
                      dstname = os.path.join(dst, suffix)
                      i+=1
                  try:
                      if symlinks and os.path.islink(srcname):
                          linkto = os.readlink(srcname)
                          os.symlink(linkto, dstname)
                      elif os.path.isdir(srcname):
                          _copytree(srcname, dstname, symlinks, ignore)
                      else:
                          shutil.copy2(srcname, dstname)
                  except (IOError, os.error) as why:
                      errors.append((srcname, dstname, str(why)))
                  # catch the Error from the recursive copytree so that we can
                  # continue with other files
                  except BaseException as err:
                      errors.extend(err.args[0])
              try:
                  shutil.copystat(src, dst)
              except WindowsError:
                  # can't copy file access times on Windows
                  pass
              except OSError as why:
                  errors.extend((src, dst, str(why)))
              if errors:
                  raise BaseException(errors)
          
          导入shutil
          导入操作系统
          def_copytree(src、dst、symlinks=False、ignore=None):
          """
          这是shutil.copytree的改进版本,允许写入到
          现有文件夹,不覆盖现有文件,而是附加
          将~1添加到文件名并将其添加到目标路径。
          """
          name=os.listdir(src)
          如果“忽略”不是“无”:
          忽略的名称=忽略(src,名称)
          其他:
          忽略_name=set()
          如果操作系统路径不存在(dst):
          os.makedirs(dst)
          shutil.copystat(src,dst)
          错误=[]
          对于名称中的名称:
          如果忽略了\u名称中的名称:
          持续
          srcname=os.path.join(src,name)
          dstname=os.path.join(dst,name)
          i=1
          当os.path.exists(dstname)而不是os.path.isdir(dstname)时:
          零件=名称。拆分('.'))
          文件名=“”
          文件扩展名=零件[-1]
          #创建一个新文件名,在名称和扩展名之间插入~1
          对于范围内的j(透镜(零件)-1):
          文件名+=零件[j]
          如果jdef predict_error(src, dst):  
              if os.path.exists(dst):
                  src_isdir = os.path.isdir(src)
                  dst_isdir = os.path.isdir(dst)
                  if src_isdir and dst_isdir:
                      pass
                  elif src_isdir and not dst_isdir:
                      yield {dst:'src is dir but dst is file.'}
                  elif not src_isdir and dst_isdir:
                      yield {dst:'src is file but dst is dir.'}
                  else:
                      yield {dst:'already exists a file with same name in dst'}
          
              if os.path.isdir(src):
                  for item in os.listdir(src):
                      s = os.path.join(src, item)
                      d = os.path.join(dst, item)
                      for e in predict_error(s, d):
                          yield e
          
          
          def copytree(src, dst, symlinks=False, ignore=None, overwrite=False):
              '''
              would overwrite if src and dst are both file
              but would not use folder overwrite file, or viceverse
              '''
              if not overwrite:
                  errors = list(predict_error(src, dst))
                  if errors:
                      raise Exception('copy would overwrite some file, error detail:%s' % errors)
          
              if not os.path.exists(dst):
                  os.makedirs(dst)
                  shutil.copystat(src, dst)
              lst = os.listdir(src)
              if ignore:
                  excl = ignore(src, lst)
                  lst = [x for x in lst if x not in excl]
              for item in lst:
                  s = os.path.join(src, item)
                  d = os.path.join(dst, item)
                  if symlinks and os.path.islink(s):
                      if os.path.lexists(d):
                          os.remove(d)
                      os.symlink(os.readlink(s), d)
                      try:
                          st = os.lstat(s)
                          mode = stat.S_IMODE(st.st_mode)
                          os.lchmod(d, mode)
                      except:
                          pass  # lchmod not available
                  elif os.path.isdir(s):
                      copytree(s, d, symlinks, ignore)
                  else:
                      if not overwrite:
                          if os.path.exists(d):
                              continue
                      shutil.copy2(s, d)
          
          import shutil
          import os
          
          
          def _copytree(src, dst, symlinks=False, ignore=None):
              """
              This is an improved version of shutil.copytree which allows writing to
              existing folders and does not overwrite existing files but instead appends
              a ~1 to the file name and adds it to the destination path.
              """
          
              names = os.listdir(src)
              if ignore is not None:
                  ignored_names = ignore(src, names)
              else:
                  ignored_names = set()
          
              if not os.path.exists(dst):
                  os.makedirs(dst)
                  shutil.copystat(src, dst)
              errors = []
              for name in names:
                  if name in ignored_names:
                      continue
                  srcname = os.path.join(src, name)
                  dstname = os.path.join(dst, name)
                  i = 1
                  while os.path.exists(dstname) and not os.path.isdir(dstname):
                      parts = name.split('.')
                      file_name = ''
                      file_extension = parts[-1]
                      # make a new file name inserting ~1 between name and extension
                      for j in range(len(parts)-1):
                          file_name += parts[j]
                          if j < len(parts)-2:
                              file_name += '.'
                      suffix = file_name + '~' + str(i) + '.' + file_extension
                      dstname = os.path.join(dst, suffix)
                      i+=1
                  try:
                      if symlinks and os.path.islink(srcname):
                          linkto = os.readlink(srcname)
                          os.symlink(linkto, dstname)
                      elif os.path.isdir(srcname):
                          _copytree(srcname, dstname, symlinks, ignore)
                      else:
                          shutil.copy2(srcname, dstname)
                  except (IOError, os.error) as why:
                      errors.append((srcname, dstname, str(why)))
                  # catch the Error from the recursive copytree so that we can
                  # continue with other files
                  except BaseException as err:
                      errors.extend(err.args[0])
              try:
                  shutil.copystat(src, dst)
              except WindowsError:
                  # can't copy file access times on Windows
                  pass
              except OSError as why:
                  errors.extend((src, dst, str(why)))
              if errors:
                  raise BaseException(errors)
          
          import os,shutil
          
          def copydir(src, dst):
            h = os.getcwd()
            src = r"{}".format(src)
            if not os.path.isdir(dst):
               print("\n[!] No Such directory: ["+dst+"] !!!")
               exit(1)
          
            if not os.path.isdir(src):
               print("\n[!] No Such directory: ["+src+"] !!!")
               exit(1)
            if "\\" in src:
               c = "\\"
               tsrc = src.split("\\")[-1:][0]
            else:
              c = "/"
              tsrc = src.split("/")[-1:][0]
          
            os.chdir(dst)
            if os.path.isdir(tsrc):
              print("\n[!] The Directory Is already exists !!!")
              exit(1)
            try:
              os.mkdir(tsrc)
            except WindowsError:
              print("\n[!] Error: In[ {} ]\nPlease Check Your Dirctory Path !!!".format(src))
              exit(1)
            os.chdir(h)
            files = []
            for i in os.listdir(src):
              files.append(src+c+i)
            if len(files) > 0:
              for i in files:
                  if not os.path.isdir(i):
                      shutil.copy2(i, dst+c+tsrc)
          
            print("\n[*] Done ! :)")
          
          copydir("c:\folder1", "c:\folder2")
          
          # Recusively copies the content of the directory src to the directory dst.
          # If dst doesn't exist, it is created, together with all missing parent directories.
          # If a file from src already exists in dst, the file in dst is overwritten.
          # Files already existing in dst which don't exist in src are preserved.
          # Symlinks inside src are copied as symlinks, they are not resolved before copying.
          #
          def copy_dir(src, dst):
              dst.mkdir(parents=True, exist_ok=True)
              for item in os.listdir(src):
                  s = src / item
                  d = dst / item
                  if s.is_dir():
                      copy_dir(s, d)
                  else:
                      shutil.copy2(str(s), str(d))
          
          import shutil
          
          shutil.copytree('bar', 'foo')
          shutil.copytree('baz', 'foo', dirs_exist_ok=True)