Pythonで「ファイルコピー」を業務レベルで使いこなす
業務自動化でファイルコピーは、ほぼ必ずと言っていいほど登場します。
「毎日生成されるレポートをバックアップフォルダにコピーする」「特定の拡張子のファイルだけを別フォルダに集める」「処理前に元データを退避しておく」──こういう作業は、全部ファイルコピーの応用です。
Pythonでは、標準ライブラリの shutil モジュールを使うことで、シンプルかつ安全にファイルコピーを行えます。
ここから、初心者向けに「まずこれだけ押さえればOK」というところから、実務でそのまま使えるテンプレートまで、一気に整理していきます。
ファイルコピーの主役:shutil.copy と shutil.copy2
shutilモジュールとは何者か
shutil は「shell utilities」の略で、シェル(コマンドプロンプトやターミナル)でやっているようなファイル操作を、Pythonから簡単に扱えるようにした標準モジュールです
インストールは不要で、import shutil と書くだけで使えます。
ファイルコピーでよく使うのは、次の2つです。
shutil.copy(src, dst)
ファイルの中身とパーミッション(権限)をコピーする。メタデータ(作成日時など)はあまり気にしない場合向け。
shutil.copy2(src, dst)
できる限りメタデータ(作成日時・更新日時など)も含めてコピーする。より「元ファイルに近い状態でコピーしたい」場合向け。
初心者のうちは「細かいメタデータは気にしない」ことが多いので、まずは shutil.copy から慣れていくと良いです。
いちばんシンプルなコピーコード
まずは「1つのファイルを、別の場所にコピーする」最小コードを見てみましょう。
import shutil
src = "data/report.txt" # コピー元
dst = "backup/report_backup.txt" # コピー先
shutil.copy(src, dst)
print("コピー完了")
Pythonこのコードは、data/report.txt の内容を backup/report_backup.txt にコピーします。
もし backup/report_backup.txt がすでに存在していれば、何の確認もなく上書きされます。ここが実務上の重要ポイントです。
重要ポイントを深掘り:src と dst の意味と挙動
dst が「ファイル名」か「フォルダ名」かで挙動が変わる
shutil.copy(src, dst) の第二引数 dst は、少しクセがあります。dst が「既存のフォルダ」なのか、「ファイルパス」なのかで挙動が変わるからです。
次の2パターンを比べてみましょう。
import shutil
# パターン1: dst を「ファイルパス」として指定
shutil.copy("data/report.txt", "backup/report_backup.txt")
# パターン2: dst を「既存のフォルダ」として指定
shutil.copy("data/report.txt", "backup")
Pythonパターン1では、「backup/report_backup.txt」というファイルが作られます。
パターン2では、「backup」フォルダの中に「report.txt」という名前でコピーされます(元ファイル名がそのまま使われるイメージです)。
ここで特に気をつけたいのは、「dst に存在しないフォルダパスを指定しても、そのフォルダは自動では作られない」という点です。
つまり、"backup/2024" というフォルダが存在しない状態でそこを指定すると、エラーになります。
コピー前に「フォルダがあるか」を確認する
業務自動化では、スクリプトが夜中に自動実行されることも多く、「フォルダがなかったからエラーで止まっていた」ことに気づくのが翌日…という事故が起きがちです。
そのため、コピー前にフォルダを作っておくテンプレートを覚えておくと安心です。
import os
import shutil
src = "data/report.txt"
dst_dir = "backup"
dst = os.path.join(dst_dir, "report_backup.txt")
# フォルダがなければ作る
os.makedirs(dst_dir, exist_ok=True)
shutil.copy(src, dst)
print("コピー完了:", dst)
Pythonos.makedirs(..., exist_ok=True) は、「フォルダがなければ作る、あれば何もしない」という便利な関数です。
この一行をテンプレートとしてセットで覚えておくと、フォルダ関連のエラーをかなり減らせます。
例題①:毎日生成されるレポートを日付付きでバックアップする
シナリオのイメージ
例えば、毎日 data/report.csv が更新されるとします。
これを「日付付きのファイル名」で backup フォルダにコピーしておきたい、というのは典型的な業務自動化です。
最終的に、次のようなファイルが並ぶイメージです。
backup/report_2024-01-01.csvbackup/report_2024-01-02.csvbackup/report_2024-01-03.csv
コード例と解説
import os
import shutil
from datetime import date
src = "data/report.csv"
today = date.today().strftime("%Y-%m-%d")
dst_dir = "backup"
dst_name = f"report_{today}.csv"
dst = os.path.join(dst_dir, dst_name)
os.makedirs(dst_dir, exist_ok=True)
shutil.copy(src, dst)
print("バックアップ完了:", dst)
Pythonこのコードの流れを言葉で整理すると、こうなります。
まず、date.today().strftime("%Y-%m-%d") で今日の日付を "2024-03-14" のような文字列に変換しています。
次に、その日付を使って report_2024-03-14.csv のようなファイル名を組み立てています。
最後に、os.makedirs でバックアップフォルダを用意し、shutil.copy でコピーしています。
ここでの重要ポイントは、「コピー先のファイル名を自分で組み立てている」というところです。
業務自動化では、「元ファイル名をそのまま使う」のではなく、「日付」「バージョン」「担当者名」などを組み合わせて、意味のあるファイル名を作ることがよくあります。
例題②:特定の拡張子のファイルだけをまとめてコピーする
シナリオのイメージ
あるフォルダ inbox に、いろいろな種類のファイルが放り込まれているとします。
この中から「CSVファイルだけ」を csv_only フォルダにコピーしたい、というケースを考えます。
これは、「人が手作業で仕分けしていた作業」を自動化する、非常に現実的なパターンです。
コード例と解説
import os
import shutil
src_dir = "inbox"
dst_dir = "csv_only"
os.makedirs(dst_dir, exist_ok=True)
for name in os.listdir(src_dir):
src_path = os.path.join(src_dir, name)
# フォルダはスキップ(ファイルだけ対象)
if not os.path.isfile(src_path):
continue
# 拡張子が .csv のものだけコピー
if not name.lower().endswith(".csv"):
continue
dst_path = os.path.join(dst_dir, name)
shutil.copy(src_path, dst_path)
print("コピー:", src_path, "→", dst_path)
Pythonこのテンプレートには、業務自動化でよく使う考え方が詰まっています。
まず、os.listdir(src_dir) で「候補を全部取る」。
次に、os.path.isfile で「ファイルだけ」に絞る。
さらに、name.lower().endswith(".csv") で「拡張子が .csv のものだけ」に絞る。
最後に、shutil.copy でコピーする。
この「候補を全部取る → 条件で絞る → 処理する」という流れは、ファイルコピーに限らず、業務自動化の基本パターンとしてそのまま覚えてしまって構いません。
例題③:上書き事故を防ぐ「安全コピー」テンプレート
なぜ「上書きチェック」が大事なのか
shutil.copy や shutil.copy2 は、コピー先に同名ファイルがあっても、何の警告もなく上書きします。
人間が手でやるときは「上書きしますか?」と聞いてくれますが、スクリプトは黙って実行します。
「昨日までのバックアップが全部上書きされて消えていた」という事故を防ぐために、「コピー先がすでに存在していたらどうするか」を自分で決めておく必要があります。
上書きしない安全コピーの例
import os
import shutil
def safe_copy(src, dst):
if os.path.exists(dst):
print("警告: すでに存在するためコピーをスキップしました →", dst)
return
# 必要ならフォルダを作成
dst_dir = os.path.dirname(dst)
if dst_dir:
os.makedirs(dst_dir, exist_ok=True)
shutil.copy(src, dst)
print("コピー完了:", dst)
src = "data/report.txt"
dst = "backup/report.txt"
safe_copy(src, dst)
Pythonこの safe_copy 関数は、次のようなポリシーを持っています。
コピー先がすでに存在していたら、上書きせずにスキップする。
存在しない場合だけ、フォルダを作成してからコピーする。
業務によっては、「上書きする前にリネームして退避する」「上書きするが、ログに必ず記録する」など、別のポリシーを採用することもあります。
大事なのは、「何も考えずに上書きする」のではなく、「どう振る舞うかを自分で決めてコードに書く」ことです。
shutil.copy と shutil.copy2 の違いをどう使い分けるか
メタデータをどこまで気にするか
shutil.copy と shutil.copy2 の違いは、「メタデータ(作成日時・更新日時など)をどこまでコピーするか」です。
shutil.copy
ファイルの中身とパーミッション(権限)をコピーする。作成日時などはあまり気にしない。
shutil.copy2
可能な限りメタデータもコピーする。より「元ファイルに近い状態」でコピーしたいときに使う。
例えば、「ログファイルを別の場所にバックアップするだけ」であれば、shutil.copy で十分なことが多いです。
一方、「監査用に、元ファイルと同じタイムスタンプで保管しておきたい」といった要件がある場合は、shutil.copy2 を選ぶ価値があります。
ただし、copy2 はメタデータを書き換える権限が必要になるため、環境によっては権限エラーが出やすくなることがあります。
「まずは確実に動かしたい」という段階では、copy から始めて、必要になったら copy2 に切り替える、という順番がおすすめです。
まとめ:ファイルコピーは「業務自動化の入り口」かつ「安全設計の練習場」
ここまで見てきたように、ファイルコピーは単なる「コピー」ではなく、業務自動化の中で次のような役割を持ちます。
元データを壊さないための「保険」としてのバックアップ。
人がやっていた仕分け作業を置き換える「自動仕分け」としてのコピー。
日付やバージョンを付けて履歴を残す「簡易バージョン管理」としてのコピー。
その中で、次のポイントを意識してコードを書くと、一気にプロっぽくなります。
コピー先がフォルダなのかファイルなのかを意識する。
フォルダがなければ os.makedirs(..., exist_ok=True) で用意する。
上書きするかどうかのポリシーを自分で決めて、コードに明示する。
必要に応じて shutil.copy2 でメタデータも含めてコピーする。
もしよければ、今あなたのPCにある「とりあえずバックアップを取りたいファイル」を1つ決めて、上のテンプレートの src と dst を書き換えて実行してみてください。
「自分のファイルが、Pythonのコード一行で安全にコピーされる」という感覚がつかめると、その先の自動化アイデアがどんどん出てくるはずです。
