検索
連載

[解決!Python]ファイルやディレクトリをコピーするには解決!Python

shutilモジュールが提供するcopy/copy2/copytree関数を使って、ファイルやディレクトリをコピーする方法を紹介する

PC用表示 関連情報
Share
Tweet
LINE
Hatena
「解決!Python」のインデックス

連載目次

import shutil

with open('a.txt', 'w'):  # サンプルファイルの作成
    pass

ret = shutil.copy('a.txt', 'b.txt')
print(ret)  # b.txt:コピー後のファイル名が戻り値

shutil.copy('b.txt', 'a.txt'# OK:既存ファイルは上書きされる

# コピーされるものの比較
import os

os.chmod('a.txt', 0o777# a.txtファイルのパーミションを変更

shutil.copy('a.txt', 'b.txt'# パーミッションだけをコピーする
shutil.copy2('a.txt', 'c.txt'# パーミッション以外の属性もコピーする
shutil.copyfile('a.txt', 'd.txt'# 属性をコピーしない

# ファイルをディレクトリの下にコピー
os.mkdir('foo'# サンプルディレクトリの作成

ret = shutil.copy('a.txt', 'foo'# dstにディレクトリを指定する
print(ret)  # foo/a.txt:指定したディレクトリの下にファイルをコピー

shutil.copy2('b.txt', 'foo/bar'# b.txtがfoo/barファイルとしてコピーされる

# ディレクトリのコピー
ret = shutil.copytree('foo', 'bar')
print(ret)  # bar:コピー先のディレクトリ名が戻り値

shutil.copytree('a.txt', 'baz'# NotADirectoryError
shutil.copytree('foo', 'a.txt'# FileExistsError

# 既存のディレクトリに再帰的にコピーする
shutil.copytree('foo', 'bar'# FileExistsError
shutil.copytree('foo', 'bar', dirs_exist_ok=True# OK

# コピーに使用する関数を指定する
shutil.copytree('foo', 'baz', copy_function=shutil.copy)

# コピーしないものを指定
from shutil import ignore_patterns

shutil.copytree('.', 'qux', ignore=ignore_patterns('foo', 'bar', 'baz', '*.py'))


関数 コピーするもの 動作
copy(src, dst) ファイル srcに指定されるファイルをdstにコピーする。dstにはファイルやディレクトリを指定可能。ファイルのパーミッションもコピーする
copy2(src, dst) ファイル srcで指定されるファイルをdstにコピーする。dstにはディレクトリを指定可能。ファイルのパーミッション、最終アクセス時間、最終変更時間などもコピーする
copytree(src, dst) ディレクトリの内容 srcに指定されたディレクトリの内容を、dstに指定されたディレクトリに再帰的にコピーする。srcとdstにはディレクトリを指定する。コピーに使用する関数を指定するcopy_functionパラメーターや、コピー先のディレクトリが存在しているときにコピーするかを指定するdirs_exist_okパラメーター、コピーの対象外とするファイル/ディレクトリを指定するignoreパラメーターなども指定可能
copy/copy2/copytree関数の動作

ファイルのコピー

 特定のファイルをコピーするにはshutilモジュールのcopy関数かcopy2関数を使用する。これら2つの関数の違いは、コピー時にファイルのパーミッションをコピーするか(copy関数)、パーミッションに加えて最終アクセス時間、最終更新時間などの属性もコピーするか(copy2関数)である。

shutil.copy(src, dest)
shutil.copy2(src, dest)


 これらの関数はfollow_symlinksパラメーターも指定可能だが、本稿では説明は省略する。

 以下にcopy関数の使用例を示す。

import shutil

with open('a.txt', 'w'):  # サンプルファイルの作成
    pass

ret = shutil.copy('a.txt', 'b.txt')
print(ret)  # b.txt:コピー後のファイル名が戻り値


 この例では、「a.txt」というファイルを「b.txt」という名前でコピーしている。なお、copy/copy2関数の戻り値はコピーされたファイルの名前となる。なお、本稿で紹介する関数は全てsrcとdstに文字列かpathlibモジュールのPathクラスのインスタンスを指定できる。

 既存のファイルをdstに指定した場合、例外は発生せずに上書きされる。

shutil.copy('b.txt', 'a.txt'# OK:既存ファイルは上書きされる


 既に述べたが、copy関数とcopy2関数の違いはファイルのパーミッションだけをコピーするか、パーミッションに加えて最終アクセス時間、最終更新時間などの属性もコピーするかにある。そこで、上で作成したa.txtファイルの属性を変更、b.txtファイルを削除した上で以下のコードを実行し、その結果を調べてみよう。

import os

os.chmod('a.txt', 0o777# a.txtファイルのパーミションを変更

shutil.copy('a.txt', 'b.txt'# パーミッションだけをコピーする
shutil.copy2('a.txt', 'c.txt'# パーミッション以外の属性もコピーする
shutil.copyfile('a.txt', 'd.txt'# 属性をコピーしない


 この例では、copy関数とcopy2関数に加えて、shutilモジュールで定義されているcopyfile関数も使用した。copyfile関数はsrcに指定されたファイルを、destに指定されたファイルにコピーする。ただし、属性のコピーは何も行わない。copy関数とcopy2関数は内部でこの関数を使用した上で、やはりshutilモジュールで定義されているcopymode関数やcopystat関数を使って、パーミッションやその他の属性をコピーしている。

 上記のコードをmacOS上で動作するVisual Studio CodeのPython対話環境で実行した後で、等号ターミナルでa.txt/b.txt/c.txt/d.txtの各ファイルの情報を表示したところを以下に示す。

コピー関数の動作の違い
コピー関数の動作の違い

 a.txtファイルがオリジナルだ。copy関数でコピーしたb.txtファイルについてはパーミッションが同じになっているが、タイムスタンプが異なっている。一方、copy2関数でコピーしたc.txtファイルについてはパーミッションもタイムスタンプと同じだ。最後に、copyfile関数でコピーしたd.txtファイルについてはパーミッションもタイムスタンプも異なっている(なお、本稿ではcopyfile関数については詳しい説明は行わない)。

 なお、これらの関数を使っても、ファイルが持つ全てのメタデータをコピーできるわけではない点には注意されたい。詳しくはshutilモジュールのドキュメントを参照されたい。

 また、copy関数とcopy2関数でdstにディレクトリを指定すると、srcに指定したファイルがdstに指定したディレクトリ以下にコピーされる。

 以下に例を示す。

os.mkdir('foo'# サンプルディレクトリの作成

ret = shutil.copy('a.txt', 'foo'# dstにディレクトリを指定する
print(ret)  # foo/a.txt:指定したディレクトリの下にファイルをコピー


 このとき、dstに存在しないディレクトリを指定すると、その名前でファイルがコピーされるので注意しよう(存在しないディレクトリを再帰的に作るようなことはない)。

shutil.copy2('b.txt', 'foo/bar'# b.txtがfoo/barファイルとしてコピーされる


 例えば、上のコードは恐らくb.txtファイルを「foo/bar」ディレクトリにコピーするつもりだったのだろうが、実際にはb.txtファイルがfooディレクトリの下にbarというファイル名でコピーされる。

 また、深いディレクトリ階層を指定したときに、その中に存在しないディレクトリがあれば例外が発生する。

ディレクトリの再帰的なコピー

 ディレクトリを再帰的にコピーするには、shutilモジュールのcopytree関数を使用する。

shutil.copytree(src, dst, copy_function =copy2, dirs_exist_ok=False, ignore=None)


 この関数は他にもsymlinksパラメーターなどを指定可能だが、本稿では説明を省略する。

 基本的な使い方はsrcにコピー元のディレクトリを、dstにコピー先のディレクトリを指定する。

ret = shutil.copytree('foo', 'bar')
print(ret)  # bar:コピー先のディレクトリ名が戻り値


 これは上の例で作成したfooディレクトリの内容をbarディレクトリに再帰的にコピーするものだ。srcとdstにはファイルを指定すると例外が発生する。

shutil.copytree('a.txt', 'baz'# NotADirectoryError
shutil.copytree('foo', 'a.txt'# FileExistsError


 上の例の1行目ではsrcに既存のa.txtファイルを指定していて、2行目ではコピー先にやはり既存のa.txtファイルを指定しているのでどちらも例外となる。

 また、dstに既存のディレクトリを指定すると例外となる点にも注意しよう。既存のディレクトリへの再帰的なコピーを行うには以下の2行目のようにdirs_exist_okにTrueを指定する。

shutil.copytree('foo', 'bar'# FileExistsError
shutil.copytree('foo', 'bar', dirs_exist_ok=True# OK


 copytree関数はデフォルトでcopy2関数を使ってファイルのコピーを行っているが、これを変更するにはcopy_functionにコピーに使用する関数を指定する。以下は、copy関数を使用する例だ。

shutil.copytree('foo', 'baz', copy_function=shutil.copy)


 copytree関数を使って再帰的にファイルをコピーする際には、コピーの対象外となるファイルも指定できる。これにはshutilモジュールで定義されているignore_patterns関数にコピーしたくないファイルを指定したものを、ignoreパラメーターに渡せばよい。

 以下に例を示す。

from shutil import ignore_patterns

shutil.copytree('.', 'qux', ignore=ignore_patterns('foo', 'bar', 'baz', '*.py'))


 この例では、カレントディレクトリ(.)の内容をquxディレクトリにコピーしようとしているが、foo/bar/bazという名前のファイル/ディレクトリと、拡張子が「py」のファイル/ディレクトリはコピーの対象外であると指定している。これにより、上で作成した4つの.txtファイルだけがquxディレクトリにコピーされる。

shutilモジュールで定義されているファイルコピー関連の関数

 最後に、本稿で取り上げた関数と、shutilモジュールで定義されているその他のファイルコピー関連の関数を以下にまとめておく。詳細についてはshutilモジュールのドキュメントを参照されたい。

関数 コピーするもの 動作
copy(src, dst) ファイル srcに指定されるファイルをdstにコピーする。dstにはファイルやディレクトリを指定可能。ファイルのパーミッションもコピーする
copy2(src, dst) ファイル srcで指定されるファイルをdstにコピーする。dstにはディレクトリを指定可能。ファイルのパーミッション、最終アクセス時間、最終変更時間などもコピーする
copytree(src, dst) ディレクトリの内容 srcに指定されたディレクトリの内容を、dstに指定されたディレクトリに再帰的にコピーする。srcとdstにはディレクトリを指定する。コピーに使用する関数を指定するcopy_functionパラメーターや、コピー先のディレクトリが存在しているときにコピーするかを指定するdirs_exist_okパラメーター、コピーの対象外とするファイル/ディレクトリを指定するignoreパラメーターなども指定可能
copyfile(src, dst) ファイル srcで指定されるファイルをdstというファイルにコピーする。dstにディレクトリは指定できない。copy関数/copy2関数の内部で使われる
copyfileobj(fsrc, fdst) ファイルオブジェクト open関数などでオープンしたファイルオブジェクトを対象とする。copyfile関数でプラットフォームごとの高速コピーが失敗した場合に内部で使用される
copymode(src, dst) パーミッション srcで指定されるファイルのパーミッションをdstにコピーする。copy関数の内部で使われる
copystat(src, dst) パーミッション、最終アクセス時間、最終変更時間など copy2関数の内部で使われる
shutilモジュールで定義されているファイルコピー関連の関数

「解決!Python」のインデックス

解決!Python

Copyright© Digital Advantage Corp. All Rights Reserved.

[an error occurred while processing this directive]
ページトップに戻る