ファイルやディレクトリのコピーや移動を行うには、Python 標準ライブラリの shutil モジュール が提供する高水準のファイル操作 API を利用するのが簡単です。
ファイルをコピーする (shutil.copyfile, shutil.copy)
shutil.copyfile 関数
shutil.copyfile 関数 で単一のファイルをコピーできます。
import shutil
import sys
try:
shutil.copyfile('src.txt', 'dst.txt')
except Exception as e:
print('Error: {0}'.format(e), file=sys.stderr)
同名のファイルがすでに存在する場合(上記の場合は dst.txt
)は上書きされます。
shutil.copyfile
関数は次のようなエラーを発生させる可能性があります。
IsADirectoryError
… コピー先として指定したファイル名と同名のディレクトリが存在する場合。OSError
… 指定したファイル名で書き込めない場合(バージョン 3.3 以降)。SameFileError
… コピー元とコピー先のファイル名が同じ場合(バージョン 3.4 以降)。FileNotFoundError
… 存在しないディレクトリ階層(aaa/bbb/dst.txt
など)にコピーしようとした場合。
shutil.copy 関数
既存のディレクトリ以下に同じファイル名でコピーしたいときは、shutil.copyfile
の代わりに shutil.copy 関数 を使用します。
# dst という名前でコピー、あるいは dst ディレクトリ以下にコピー
shutil.copy('src.txt', 'dst')
上記のように実行すると、dst
ディレクトリがない場合は dst
というファイル名でコピーされ、dst
ディレクトリが存在する場合は dst/src.txt
としてコピーされます。
shutil.copyfile と shutil.copy の使い分け
copyfile
関数と copy
関数の振る舞いの違いをまとめておきます。
違いは、ターゲットと同じ名前のディレクトリが存在しているときの振る舞いです。
shutil.copyfile('src.txt', 'dst')
dst
が存在しないとき:dst
としてコピーdst
ファイルが存在するとき:dst
ファイルを上書きdst
ディレクトリが存在するとき: エラー (IsADirectoryError
)
shutil.copy('src.txt', 'dst')
dst
が存在しないとき:dst
としてコピーdst
ファイルが存在するとき:dst
ファイルを上書きdst
ディレクトリが存在しないとき:dst/src.txt
としてコピー
なお、shutil.copyfile
も shutil.copy
もディレクトリをコピーすることはできません(IsADirectoryError
が発生します)。
ディレクトリをコピーする (shutil.copytree)
shutil.copytree 関数 を使用すると、指定したディレクトリを丸ごとコピーできます。
次の例では、src
ディレクトリを dst
ディレクトリとしてコピーします。
import shutil
shutil.copytree('src', 'dst')
すでにカレントディレクトリに dst
という名前のファイルやディレクトリが存在する場合は FileExistsError
が発生します。
ただし、次のように dirs_exist_ok
フラグを True
に設定すると、dst
ディレクトリが存在していてもそのままコピーしようとします(dst
内のファイル群が上書きされるという動作になります)。
import shutil
shutil.copytree('src', 'dst', dirs_exist_ok=True)
shutil.copytree
関数には面白い機能が付いていて、次のように ignore
パラメーターを利用すると、グロブパターンに一致したファイルやディレクトリをコピー対象から外すことができます(バージョン 3.8 以降)。
from shutil import copytree, ignore_patterns
copytree(src, dst, ignore=ignore_patterns('*.pyc', 'tmp*'))
ファイルやディレクトリを移動する (shutil.move)
ファイルやディレクトリの移動は単純で、shutil.move 関数 一種類だけで実現できます。
import shutil
shutil.move('src', 'dst')
上記のようにすると、src
ファイル(あるいはディレクトリ)を、dst
という名前に変更します。
すでに dst
という名前のディレクトリが存在している場合は、dst
ディレクトリ内に移動させようとします(dst/src
ができる)。
つまり、Linux の mv
コマンドのように振る舞います。
確実にリネームだけを実行したい場合は、os.rename
関数を使ってください。
ファイルの存在を確認しておくのが安全 (os.path.exists)
基本的には、ファイルやディレクトリの移動やコピーを行う場合は、os.path.exists 関数 を使って、あらかじめ同名のファイルやディレクトリが存在していないかをチェックしておくのが安全です。
import os
import shutil
def check_and_copy(src, dst):
"""
ファイルをコピーします。
すでに同名のファイルが存在する場合は、確認プロンプトを表示します。
"""
if os.path.exists(dst):
if input('Overwrite?(y/n): ') != 'y':
return
shutil.copyfile(src, dst)
check_and_copy('src', 'dst')