【Python】ファイルをコピーする方法!shutil.copy()とshutil.copy2()の使い方

この記事ではPythonのファイルをコピーする関数『shutil.copy()』と『shutil.copy2()』について、

  • shutil.copy()shutil.copy2()とは
  • shutil.copy()shutil.copy2()の構文
  • shutil.copy()shutil.copy2()の使い方
    • ファイルを既存のディレクトリにコピーする方法
    • ファイルをコピー元のファイルに置き変える
  • shutil.copy()shutil.copy2()の注意点
    • 第2引数dstで新規のディレクトリパスを指定しても、ディレクトリは作成されない
    • 存在しない中間ディレクトリを第2引数dstで指定するとエラーになる
  • shutil.copy()shutil.copy2()の違い

などをサンプルコードを用いて分かりやすく説明するように心掛けています。ご参考になれば幸いです。

shutil.copy()とshutil.copy2()とは

shutil.copy()shutil.copy2()は、Pythonの標準ライブラリshutilに含まれる関数で、ファイルの内容をコピーするために使用されます。shutil.copy()shutil.copy2()では、メタデータ(作成日時や更新日時)の扱い方が異なります。

  • shutil.copy()
    • メタデータはコピーしません。
  • shutil.copy2()
    • 可能な限りメタデータもコピーします。shutil.copy()よりも詳細なコピーを行うのがshutil.copy2()です。

後ほどshutil.copy()shutil.copy2()の構文や使い方について詳しく説明しますが、まず以下に示す簡単なサンプルコードを見てみましょう。

import shutil

# コピー元ファイルパス
src_file = 'temp/file.txt'
# コピー先ディレクトリパス
dst_dir = 'temp/dir1/'

# shutil.copy()でファイルをコピー
shutil.copy(src_file, dst_dir)

# shutil.copy2()でファイルをコピー(メタデータもコピーされる)
shutil.copy2(src_file, dst_dir)

上記のサンプルコードでは、temp/file.txttemp/dir1にコピーしています。shutil.copy2()を使用すると、メタデータもコピーするようになります。

公式ドキュメント

shutil.copy()shutil.copy2()の公式ドキュメントのリンクを以下に示します。

この記事ではshutil.copy()shutil.copy2()の「使い方」や「注意点」についてできる限り分かりやすく説明しています。これらの関数の詳細を知りたい方は、公式ドキュメントをご覧ください。

shutil.copy()とshutil.copy2()の構文

shutil.copy()shutil.copy2()の構文を以下に示します。

構文

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

shutil.copy()shutil.copy2()の引数と返り値を以下に示します。

引数

  • src
    • コピー元のファイルパスです。
  • dst
    • コピー先のファイルパスまたはディレクトリパスです。
    • dstがディレクトリパスを指定している場合には、コピー元のファイルはdstの中にコピーされます。
      • ファイル名はsrcで指定したファイルパスのファイル名となります。
    • dstがファイルパスを指定している場合には、コピー元のファイルはdstの中にコピーされます。
      • ファイル名はdstで指定したファイルパスのファイル名となります。
    • dstが既に存在しているファイルパスを指定している場合には、そのファイルがコピー元のファイルに置き換えられます。

返り値(戻り値)

  • 新しく作成したファイルのパスを返します。

shutil.copy()とshutil.copy2()の使い方

以下のディレクトリ構造とします。

temp/
├── dir1/
├── dir2/
│   └── file.txt
└── file.txt

このディレクトリ構成で、shutil.copy()shutil.copy2()について、以下に示している使い方をこれから説明します。

  • ファイルを既存のディレクトリにコピーする(dstでディレクトリパスを指定した場合)
  • ファイルを既存のディレクトリにコピーする(dstでファイルパスを指定した場合)
  • ファイルをコピー元のファイルに置き変える(dstで既に存在しているファイルパスを指定した場合)

上記の使い方について順番に説明します。

ファイルを既存のディレクトリにコピーする(dstでディレクトリパスを指定した場合)

shutil.copy()shutil.copy2()の第2引数dstにディレクトリパスを指定すると、コピー元のファイルはdstの中にコピーされます。その際、ファイル名はsrcで指定したファイルパスのファイル名となります。

サンプルコード

import shutil

src_file = 'temp/file.txt'
dst_dir = 'temp/dir1/'

shutil.copy(src_file, dst_dir)

上記のサンプルコード実行後のディレクトリ構成

temp/
├── dir1/
│   └── file.txt ← 「temp/file.txt」が「temp/dir1/」の中にコピーされる
├── dir2/
│   └── file.txt
└── file.txt

なお、コピー元のファイルと同名のファイルがdstに存在している場合には、そのファイルがコピー元のファイルに置き換えられます。

サンプルコード

import shutil

src_file = 'temp/file.txt'
dst_dir = 'temp/dir2/'

shutil.copy(src_file, dst_dir)

上記のサンプルコード実行後のディレクトリ構成

temp/
├── dir1/
├── dir2/
│   └── file.txt ← コピー元のファイル(temp/file.txt)に置き換えられる
└── file.txt

ファイルを既存のディレクトリにコピーする(dstでファイルパスを指定した場合)

shutil.copy()shutil.copy2()の第2引数dstにファイルパスを指定すると、コピー元のファイルはdstの中にコピーされます。その際、ファイル名はdstで指定したファイルパスのファイル名となります。

サンプルコード

import shutil

src_file = 'temp/file.txt'
dst_file = 'temp/dir1/copied_file.txt'

shutil.copy(src_file, dst_file)

上記のサンプルコード実行後のディレクトリ構成

temp/
├── dir1/
│   └── copied_file.txt ← 「temp/file.txt」がdstで指定したファイルパスのファイル名(copied_file.txt)でコピーされる
├── dir2/
│   └── file.txt
└── file.txt

ファイルをコピー元のファイルに置き変える(dstで既に存在しているファイルパスを指定した場合)

shutil.copy()shutil.copy2()の第2引数dstに既に存在しているファイルパスを指定すると、そのファイルがコピー元のファイルに置き換えられます。

サンプルコード

import shutil

src_file = 'temp/file.txt'
dst_file = 'temp/dir2/file.txt'

shutil.copy(src_file, dst_file)

上記のサンプルコード実行後のディレクトリ構成

temp/
├── dir1/
├── dir2/
│   └── file.txt ← コピー元のファイル(temp/file.txt)に置き換えられる
└── file.txt

shutil.copy()とshutil.copy2()の注意点

shutil.copy()shutil.copy2()の注意点を以下に示します。

  • dstで新規のディレクトリパスを指定しても、ディレクトリは作成されない
  • 存在しない中間ディレクトリをdstで指定するとエラーになる

各注意点について順番に説明します。

dstで新規のディレクトリパスを指定しても、ディレクトリは作成されない

shutil.copy()shutil.copy2()の第2引数dstに新規のディレクトリパスを指定しても、ディレクトリは作成されません。例えば、temp/dir3と指定すると、temp/dir3の中にファイルがコピーされるのではなく、dir3というファイルとしてコピーされるので注意してください。

サンプルコード

import shutil

src_file = 'temp/file.txt'
dst_path = 'temp/dir3'

shutil.copy(src_file, dst_path)

上記のサンプルコード実行後のディレクトリ構成

temp/
├── dir1/
├── dir2/
│   └── file.txt
├── file.txt
└── dir3 ← 「temp/file.txt」がdir3というファイルとしてコピーされる

なお、temp/dir3//を付けると、指定するとエラーになります。

サンプルコード

import shutil

src_file = 'temp/file.txt'
dst_path = 'temp/dir3/'

shutil.copy(src_file, dst_path)

エラーメッセージ

OSError: [Errno 22] Invalid argument: 'temp/dir3/'

存在しない中間ディレクトリをdstで指定するとエラーになる

shutil.copy()shutil.copy2()の第2引数dstに存在しない中間ディレクトリがあると、エラーになります。例えば、temp/dir1/new_dir/file.txtのように指定するとエラーになります。dir1new_dirという中間ディレクトリが作成され、その中にfile.txtというファイル名でコピー元ファイルがコピーされるわけではありません。

サンプルコード

import shutil

src_file = 'temp/file.txt'
dst_path = 'temp/dir1/new_dir/file.txt'

shutil.copy(src_file, dst_path)

上記のサンプルコード実行後に期待するディレクトリ構成(実際はこうならない)

temp/
├── dir1/
│   └── new_dir/
│       └── file.txt ← コピーされたファイル
├── dir2/
│   └── file.txt
└── file.txt

エラーメッセージ

FileNotFoundError: [Errno 2] No such file or directory: 'temp/dir1/new_dir/file.txt'

shutil.copy()とshutil.copy2()の違い

shutil.copy2()の使い方はshutil.copy()と同じですが、メタデータ(作成日時・更新日時など)の扱いが異なります。

  • shutil.copy()
    • メタデータをコピーしません。例えば、コピーしたファイルの更新日時はコピーした時刻となります。
  • shutil.copy2()
    • メタデータをできる限りコピーします。コピー元とコピー先の更新日時が同じになります。

サンプルコード

import shutil
import os

src_file = 'temp/file.txt'
dst_file_copy1 = 'temp/dir1/copied_file_copy1.txt'
dst_file_copy2 = 'temp/dir1/copied_file_copy2.txt'

# shutil.copy()でコピー
shutil.copy(src_file, dst_file_copy1)
# shutil.copy2()でコピー
shutil.copy2(src_file, dst_file_copy2)

# 更新日時の確認
print('src:', os.path.getmtime(src_file))
print('copy:', os.path.getmtime(dst_file_copy1))
print('copy2:', os.path.getmtime(dst_file_copy2))

上記のサンプルコードを実行すると、shutil.copy()でコピーしたファイルの更新日時はコピーした時刻となり、shutil.copy2()でコピーしたファイルの更新日時は元のファイルと同じであることが確認できます。

なお、shutil.copy2()でもすべてのメタデータが保持されるわけではないので注意してください。

高水準のファイルコピー関数 (shutil.copy()shutil.copy2()) でも、ファイルのメタデータの全てをコピーすることはできません。

POSIXプラットフォームでは、これはACLやファイルのオーナー、グループが失われることを意味しています。 Mac OSでは、リソースフォーク(resource fork)やその他のメタデータが利用されません。これは、リソースが失われ、ファイルタイプや生成者コード(creator code)が正しくなくなることを意味しています。 Windowsでは、ファイルオーナー、ACL、代替データストリームがコピーされません。

shutil --- 高水準のファイル操作

本記事のまとめ

この記事ではPythonのファイルをコピーする関数『shutil.copy()』と『shutil.copy2()』について、以下の内容を説明しました。

  • shutil.copy()shutil.copy2()とは
  • shutil.copy()shutil.copy2()の構文
  • shutil.copy()shutil.copy2()の使い方
    • ファイルを既存のディレクトリにコピーする方法
    • ファイルをコピー元のファイルに置き変える
  • shutil.copy()shutil.copy2()の注意点
    • 第2引数dstで新規のディレクトリパスを指定しても、ディレクトリは作成されない
    • 存在しない中間ディレクトリを第2引数dstで指定するとエラーになる
  • shutil.copy()shutil.copy2()の違い

お読み頂きありがとうございました。