306

barという名前のディレクトリ(1 つ以上のファイルを含む) と という名前のディレクトリ(1 つ以上のファイルも含む) を含むディレクトリから、次のコードを実行します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'

次のように入力した場合と同じように動作するようにします。

$ mkdir foo
$ cp bar/* foo/
$ cp baz/* foo/

各ファイルをshutil.copy()にコピーするために使用する必要がありますか? ('bar' の内容を 'foo' に既にコピーした後?) または、より簡単な/より良い方法はありますか?bazfooshutil.copytree()

4

15 に答える 15

386

標準ライブラリの一部であるソリューションを次に示します。

from distutils.dir_util import copy_tree
copy_tree("/a/b/c", "/x/y/z")

この同様の質問を参照してください。

Pythonでディレクトリの内容をディレクトリにコピーする

于 2015-06-24T23:56:31.203 に答える
231

この規格の制限は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

  • ツリーのルートディレクトリのパラメータを尊重symlinksしません。ignoresrc
  • ;shutil.Errorのルートレベルでエラーが発生することはありません。src
  • サブツリーのコピー中にエラーが発生した場合、shutil.Error他のサブツリーをコピーして単一の結合を発生させるのではなく、そのサブツリーに対して発生しますshutil.Error
于 2012-09-20T14:10:22.133 に答える
85

Python 3.8 では、次のdirs_exist_ok引数が導入されましたshutil.copytree

srcをルートとするディレクトリ ツリー全体をdstという名前のディレクトリに再帰的にコピーし、宛先ディレクトリを返します。dirs_exist_okは、 dstまたは見つからない親ディレクトリが既に存在する場合に例外を発生させるかどうかを決定します。

したがって、Python 3.8+ では次のように動作します。

import shutil

shutil.copytree('bar', 'foo')
shutil.copytree('baz', 'foo', dirs_exist_ok=True)
于 2019-11-18T14:31:22.853 に答える
70

上記の関数が常にファイルをソースから宛先にコピーしようとする関数に対する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ビルドと一緒に使用しています。コンパイルするたびに、ファイルのセット全体をコピーする必要はないかもしれませんが、変更されたファイルだけをコピーする必要があるので、それは私を大いに助けました。

于 2012-12-11T06:04:54.280 に答える
39

atzz と Mital Vora に触発されたマージ 1:

#!/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が既に存在する場合は失敗しません
于 2014-03-11T17:14:16.563 に答える
8

ドキュメントは、宛先ディレクトリが存在してはならないことを明示的に述べています:

によって指定された宛先ディレクトリは、dstまだ存在していてはなりません。親ディレクトリが欠落しているだけでなく、作成されます。

あなたの最善の策はos.walk、2番目以降のすべてのディレクトリ、copy2ディレクトリ、およびファイルであり、ディレクトリに対して追加copystatを行うことだと思います。結局のところcopytree、ドキュメントで説明されているとおりです。またはcopycopystat各ディレクトリ/ファイルとos.listdirの代わりにos.walk.

于 2009-12-08T17:59:27.113 に答える
1

これは、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 のコメントを外して、移動機能にします。

于 2014-11-27T01:43:32.690 に答える
0

以前のソリューションには、通知や例外なしにsrc上書きされる可能性がある問題があります。dst

predict_errorコピー前にエラーを予測するメソッドを追加します。copytree主に Cyrille Pontvieux のバージョンに基づいています。

すべてのエラーを修正するまでpredict_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)
于 2016-07-13T08:31:04.433 に答える
0

これが同じタスクの私のバージョンです::

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)
于 2014-06-28T16:45:47.397 に答える
0

これは、このスレッドに触発された、より厳密に模倣したバージョンdistutils.file_util.copy_fileです。

updateonlydsttrue の場合は bool であり、既存のファイルよりも更新日が新しいファイルのみをコピーしますforceupdate

ignoreforceupdateまた、ファイル名またはフォルダー/ファイル名の相対 リストを期待し、またはsrcに似た Unix スタイルのワイルドカードを受け入れます。globfnmatch

dryrunこの関数は、コピーされた (またはTrue の場合はコピーされる) ファイルのリストを返します。

import os
import shutil
import fnmatch
import stat
import itertools

def copyToDir(src, dst, updateonly=True, symlinks=True, ignore=None, forceupdate=None, dryrun=False):

    def copySymLink(srclink, destlink):
        if os.path.lexists(destlink):
            os.remove(destlink)
        os.symlink(os.readlink(srclink), destlink)
        try:
            st = os.lstat(srclink)
            mode = stat.S_IMODE(st.st_mode)
            os.lchmod(destlink, mode)
        except OSError:
            pass  # lchmod not available
    fc = []
    if not os.path.exists(dst) and not dryrun:
        os.makedirs(dst)
        shutil.copystat(src, dst)
    if ignore is not None:
        ignorepatterns = [os.path.join(src, *x.split('/')) for x in ignore]
    else:
        ignorepatterns = []
    if forceupdate is not None:
        forceupdatepatterns = [os.path.join(src, *x.split('/')) for x in forceupdate]
    else:
        forceupdatepatterns = []
    srclen = len(src)
    for root, dirs, files in os.walk(src):
        fullsrcfiles = [os.path.join(root, x) for x in files]
        t = root[srclen+1:]
        dstroot = os.path.join(dst, t)
        fulldstfiles = [os.path.join(dstroot, x) for x in files]
        excludefiles = list(itertools.chain.from_iterable([fnmatch.filter(fullsrcfiles, pattern) for pattern in ignorepatterns]))
        forceupdatefiles = list(itertools.chain.from_iterable([fnmatch.filter(fullsrcfiles, pattern) for pattern in forceupdatepatterns]))
        for directory in dirs:
            fullsrcdir = os.path.join(src, directory)
            fulldstdir = os.path.join(dstroot, directory)
            if os.path.islink(fullsrcdir):
                if symlinks and dryrun is False:
                    copySymLink(fullsrcdir, fulldstdir)
            else:
                if not os.path.exists(directory) and dryrun is False:
                    os.makedirs(os.path.join(dst, dir))
                    shutil.copystat(src, dst)
        for s,d in zip(fullsrcfiles, fulldstfiles):
            if s not in excludefiles:
                if updateonly:
                    go = False
                    if os.path.isfile(d):
                        srcdate = os.stat(s).st_mtime
                        dstdate = os.stat(d).st_mtime
                        if srcdate > dstdate:
                            go = True
                    else:
                        go = True
                    if s in forceupdatefiles:
                        go = True
                    if go is True:
                        fc.append(d)
                        if not dryrun:
                            if os.path.islink(s) and symlinks is True:
                                copySymLink(s, d)
                            else:
                                shutil.copy2(s, d)
                else:
                    fc.append(d)
                    if not dryrun:
                        if os.path.islink(s) and symlinks is True:
                            copySymLink(s, d)
                        else:
                            shutil.copy2(s, d)
    return fc
于 2016-02-12T20:43:38.770 に答える
-6

最速かつ最も簡単な方法は、Pythonにシステムコマンドを呼び出すことだと思います...

例..

import os
cmd = '<command line call>'
os.system(cmd)

ディレクトリを tar および gzip します。目的の場所でディレクトリを unzip および untar します。

ええ?

于 2009-12-08T18:00:05.490 に答える