Pythonでファイルをコピーする方法4選: copyfile, copy, copy2, copytree

262, 2021-06-03

目次

Pythonでファイルをコピーする方法

Pythonではライブラリを使うとファイルを簡単にコピーすることができます。
ライブラリはshutilという標準ライブラリを使います。

この記事ではshutilの関数を使ってファイルをコピーする方法を解説します。
結論から言うとファイルのコピーは↓のようにします。

import shutil


shutil.copyfile('sample/src/file1.txt', 'sample/dst/file2.txt')
shutil.copy('sample/src/file1.txt', 'sample/dst/file3.txt')
shutil.copy2('sample/src/file1.txt', 'sample/dst/file4.txt')
shutil.copytree('sample/src/', 'sample/dst/src')
# sample/dst/
# ├── file2.txt
# ├── file3.txt
# ├── file4.txt
# └── src
#     └── file1.txt

具体的には↓を見ていきます。

  • 主要4関数の違い

  • copyfile()の使い方

  • copy()の使い方

  • copy2()の使い方

  • copytree()の使い方

主要4関数の違い

copyfile(), copy(), copy2(), copytree()の違いを具体的に表にしてみました。

関数名 コピーするもの コピーの挙動
copyfile ファイル ファイル内容のみをコピーし、ファイルのパーミッション、メタデータをコピーしない。
copy ファイル ファイル内容をコピーし、パーミッションもコピーする。
copy2 ファイル ファイル内容をコピーし、パーミッションやメタデータ(作成日、更新日)もコピーするように努める。
copytree ディレクトリ ディレクトリを丸ごとコピーする。

とりあえず何でもかんでもコピーしたい場合はcopy2()を使っておけば良さそうです。
ただcopy2()も絶対的にメタデータのコピーが成功するという訳ではないみたいなので、その辺は注意が必要です。
それからできるだけ完璧にディレクトリをコピーしたい場合はcopytree()の引数(copy_function)にcopy2を指定すれば良さそうです。
メタデータやパーミッションが重要でない場合はcopyfile()のほうがcopystat()を呼び出さない分動作は早くなりそうです。

copyfile()の使い方

shutil.copyfile()は第1引数に指定されたファイルを第2引数にコピーします。

copyfile()の構造は↓のようになっています。

shutil.copyfile(src, dst, *, follow_symlinks=True)

第2引数のdstは書き込み可能である必要があります。
dstが書き込み不可であった場合、copyfile()は例外OSErrorを送出します。
dstがすでに存在する場合は上書きされます。

第3引数のfollow_symlinksFalsesrcがシンボリックリンクであった場合、copyfile()srcの内容をコピーせずシンボリックリンクを作成します。

copyfile()copy()copy2()と違ってコピー時にファイルのパーミッションやメタデータを維持しません
そのため日付などはコピー元と異なる場合があります。

↓がサンプルコードです。

import shutil


shutil.copyfile('sample/src/file1.txt', 'sample/dst/file2.txt')

↑の場合sample/src/file1.txtというファイルがsample/dst/file2.txtにコピーされます。

copy()の使い方

shutil.copy()は第1引数に指定されたファイルを第2引数にコピーします。

copy()は↓のような構造になっています。

shutil.copy(src, dst, *, follow_symlinks=True)

copy()copyfile()と同様に第3引数のfollow_symlinksFalsesrcがシンボリックだった場合は、単純にシンボリックリンクを作成します。

copy()はファイルの内容の他に、ファイルのパーミッションをコピーします。
ファイルの作成日や更新日などのメタデータはコピーしません

↓がサンプルコードです。

import shutil


shutil.copy('sample/src/file1.txt', 'sample/dst/file2.txt')

↑の場合もsample/src/file1.txtというファイルがsample/dst/file2.txtにコピーされます。

copy2()の使い方

shutil.copy2()は第1引数に指定されたファイルを第2引数にコピーします。

copy2()の構造は↓のようになっています。

shutil.copy2(src, dst, *, follow_symlinks=True)

copy2()も第3引数にfollow_symlinksを持っていますが、これがFalsesrcがシンボリックリンクだった場合は、単純にシンボリックリンクが作成されます。

copy2()はメタデータをコピーしようとします。
メタデータとはファイルの作成日、更新日などのデータのことです。
copy2()はこれらのデータのコピーのために内部的にcopystat()を使います。

↓がサンプルコードです。

import shutil


shutil.copy2('sample/src/file1.txt', 'sample/dst/file2.txt')

↑の場合もsample/src/file1.txtというファイルがsample/dst/file2.txtにコピーされます。

copytree()の使い方

ディレクトリを丸ごとコピーしたい場合はcopytree()を使います。
copytree()は第1引数に指定されたディレクトリを第2引数にコピーします。

copytree()は↓のような構造になっています。

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

srcがコピー元でdstがコピー先です。
サンプルコードは↓です。

import shutil


shutil.copytree('sample/src/', 'sample/dst/src')

symlinksTrueの場合は、ディレクトリ内のシンボリックリンクは、そのままシンボリックリンクとしてコピーされます。
symlinksFalseの場合は、シンボリックリンクであっても中身をコピーして新しくディレクトリを作成します。

ignoreには関数を指定します。この関数の返り値のファイル名をcopytree()はコピー時に無視します。
この関数の第1引数には現在走査中のディレクトリを表すオブジェクト、第2引数にはディレクトリの内容を表すオブジェクトが渡されます。
この関数の挙動は↓のようなコードで確認することができます。

def ignore(dir_, lis):
    print(dir_, lis)
    return 'file1.txt'

shutil.copytree('sample/src/', 'sample/dst/src', ignore=ignore)

出力結果↓。

sample/src/ {'file1.txt', 'dir1', 'dir2'}
<DirEntry 'dir1'> {'file1.txt', 'file2.txt'}
<DirEntry 'dir2'> {'file1.txt', 'file2.txt'}

↑のコードを実行するとsample/src以下のファイルがコピーされます。
そのときfile1.txtは除外してコピーされます。

copy_functionにはコピーで使用する関数を指定します。デフォルトではcopy2()です。
copyfile()を指定する場合は↓のようになり、

shutil.copytree('sample/src/', 'sample/dst/src', copy_function=shutil.copyfile)

copy()を指定する場合は↓のようになります。

shutil.copytree('sample/src/', 'sample/dst/src', copy_function=shutil.copy)

symlinksFalseで、シンボリックリンクが壊れている場合はコピーに失敗し例外がエラーリストに追加される場合がありますが、ignore_dangling_symlinksTrueに設定するとこのエラーが送出されなくなります。

dirs_exist_okTrueの場合、すでにディレクトリが存在する場合でもエラーが送出されなくなります。

copytree()はコピー先にすでにディレクトリが存在する場合は、dirs_exist_okが指定されている場合を除いてエラー(FileExistsError)が出力されます。

try:
    shutil.copytree('sample/src/', 'sample/src')
except FileExistsError as e:
    print(e)
    # [Errno 17] File exists: 'sample/src'

おわりに

今回はPythonでファイルをコピーする方法を見てみました。
コピーはプログラムの基本ですが、Pythonではshutilを使うことで簡単に行うことができます。

コピーがコピーを生み

コピーの海……

投稿者名です。64字以内で入力してください。

必要な場合はEメールアドレスを入力してください(全体に公開されます)。

投稿する内容です。