89749


以下のようなディレクトリ構造があります。

[code]

    testFolderA
        |_ copyfolder
            |_ aaa.txt
            |_ bbb.txt
            |_ ccc.txt
            |_ ddd.txt
            |_ eee.txt
    testFolderB
        |_ copyfolder
            |_ aaa.txt
            |_ ccc.txt
            |_ eee.txt
    
[/code]

Pythonで、copyfolderをディレクトリごとtestFolderAからtestFolderBにコピーしたいです。  
その際に、すでにあるファイルは上書きしないようにしたいです。

この例の場合だと、aaa.txtとccc.txtとeee.txtは既にあるのでコピーをせずに  
bbb.txtとddd.txtだけコピーしたいです。

以下のコマンドを実行したところ、エラーになってコピーできません。

[code]

    import shutil
    shutil.copytree('testFolderA/copyfolder','testFolderB/copyfolder')
    
[/code]

どのようなコードでコピーするのが効率的でしょうか？

さらに下位ディレクトリがある場合も、再帰的に処理を行い、すべてのファイルを走査し、ないものはコピー、あるものは保留をしたいです。コピー先にディレクトリがない場合はディレクトリも作成されていてほしいです。

Windows環境を想定しています。


CC BY-SA 4.0
2022-07-03T23:00:48.987
89746
2022-07-06T04:58:41.380
2022-07-04T00:19:28.510
3060
36446
question
python windows
Pythonでディレクトリ内部のファイルを上書きせずに、存在しないファイルだけコピーしたい


python 3.8
で[`shutil.copytree`](https://docs.python.org/ja/3/library/shutil.html#shutil.copytree)の引数に`dirs_exist_ok`が追加されました。  
`dirs_exist_ok=True`を指定することでエラーが発生しなくなります。

ただしこの状態ではすべてのファイルを上書きしてしまうため、`ignore`引数を使用することで存在しないファイルのみコピーすることができます。  
実際のコードは下記のサンプルコードを参考にしてください。

**サンプルコード**

[code]

    import shutil
    import os
    
    def ignore(d, l):
        retVal = [] # 存在しないファイルのリスト
        for p in l:
            # isfile ではなく exists を使うとフォルダを再帰的にコピーしてくれないので注意
            if os.path.isfile(os.path.join(dst, p)): # ignore(d, l)のdはコピー元のパスなので、dstを使わないとコピー先の存在チェックができない
                retVal.append(p)
        # 存在しないファイルを無視リストとして戻す
        return retVal
    
    src = 'testFolderA/copyfolder'
    dst = 'testFolderB/copyfolder'
    # dirs_exist_okは3.8以降使用可能
    shutil.copytree(src, dst, ignore=ignore, dirs_exist_ok=True)
    
[/code]

Windows限定ならば`Process`からrobocopyなどのコマンドを呼び出す方法も考えられますが、この回答には含みません。


CC BY-SA 4.0
2022-07-04T01:41:57.613
89749
2022-07-04T01:41:57.613
9820
89746
answer


> Pythonで、copyfolderをディレクトリごとtestFolderAからtestFolderBにコピーしたいです。  
>  その際に、すでにあるファイルは上書きしないようにしたいです。  
>  どのようなコードでコピーするのが効率的でしょうか？

効率的というか, コピーする際に `testFolderB`のディレクトリー構造が破壊されてしまうので  
(個人的には)非破壊的な手順にするでしょう … target: 第 3のディレクトリーを用意し

  1. `testFolderA` から targetへすべてコピー
  2. `testFolderB` から targetへ上書きコピー

のような手順。  
他には, ファイルやディレクトリー管理を行うのが目的なら
[アーカイブ](https://docs.python.org/ja/3/library/archiving.html) を利用するかも

  * [zipfile --- ZIP アーカイブの処理](https://docs.python.org/ja/3/library/zipfile.html)
  * [tarfile --- tar アーカイブファイルの読み書き](https://docs.python.org/ja/3/library/tarfile.html)

(tar アーカイバーに馴染みがなく, zipしか使ったこと無いなら zip 一択になるけど)

* * *

`shutil.copytree`を利用する場合:

>
> さらに下位ディレクトリがある場合も、再帰的に処理を行い、すべてのファイルを走査し、ないものはコピー、あるものは保留をしたいです。コピー先にディレクトリがない場合はディレクトリも作成されていてほしいです。
[code]

    from pathlib import Path
    import shutil
    
    def f_exists(base, dst):
        base, dst = Path(base), Path(dst)
        def _ignore(path, names):   # サブディレクトリー毎に呼び出される
            names = set(names)
            rel = Path(path).relative_to(base)
            return {f.name for f in (dst/ rel).glob('*') if f.name in names}
        return _ignore
    
    src = 'testFolderA/copyfolder'
    dst = 'testFolderB/copyfolder'
    shutil.copytree(src, dst, ignore=f_exists(src, dst), dirs_exist_ok=True)
    
[/code]


CC BY-SA 4.0
2022-07-05T10:53:44.923
89766
2022-07-06T04:58:41.380
2022-07-06T04:58:41.380
43025
43025
89746
answer