結論から言うと、shutil はファイルやフォルダのコピー、移動、削除などを扱うための標準ライブラリです。
Pythonで作業を自動化すると、処理前にファイルをバックアップしたり、出力ファイルを別フォルダへコピーしたりすることがあります。
そのような場面では、shutil.copy2() や shutil.copytree() を使うと、少ないコードで実用的なコピー処理を書けます。
この記事では、テキストファイルをバックアップフォルダへコピーする例を使って、shutil の基本を整理します。
この記事でわかること
完成コード
完成コードは次の通りです。
import shutil
from datetime import datetime
from pathlib import Path
def backup_file(source_path: Path, backup_dir: Path) -> Path:
if not source_path.is_file():
raise FileNotFoundError(f"コピー元ファイルが見つかりません: {source_path}")
backup_dir.mkdir(parents=True, exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_name = f"{source_path.stem}_{timestamp}{source_path.suffix}"
backup_path = backup_dir / backup_name
shutil.copy2(source_path, backup_path)
return backup_path
work_dir = Path("work")
source_file = work_dir / "report.txt"
source_file.parent.mkdir(parents=True, exist_ok=True)
source_file.write_text("今日の作業メモです。", encoding="utf-8")
saved_path = backup_file(source_file, work_dir / "backup")
print(f"バックアップしました: {saved_path}")このコードを実行すると、work/report.txt を作成し、work/backup フォルダに日時付きのファイル名でコピーします。
コードのポイント
このコードでは、pathlib でパスを組み立て、shutil.copy2() でファイルをコピーしています。
- コピー元がファイルかどうかを
is_file()で確認しています - バックアップ先フォルダを
mkdir()で作成しています - 日時を付けて、上書きしにくいファイル名にしています
shutil.copy2()でファイルの内容とメタ情報をコピーしています- コピーした先のパスを戻り値として返しています
実務では、コピー処理そのものよりも、コピー前の確認や上書き対策が大切です。
安全に扱うために、コピー元の存在確認と保存先の命名をセットで考えます。
コードを順番に説明します
主要な処理を分けて説明します。
1. コピー元ファイルを確認します
if not source_path.is_file():
raise FileNotFoundError(f"コピー元ファイルが見つかりません: {source_path}")source_path.is_file() は、指定したパスが実在するファイルかどうかを確認します。
存在しないファイルをコピーしようとするとエラーになるため、先に確認しておくと原因が分かりやすくなります。
ここでは、見つからない場合に FileNotFoundError を出しています。
第4章で扱った raise の考え方と同じで、処理を続けられない状態を早めに知らせるためです。
2. バックアップ先フォルダを作ります
backup_dir.mkdir(parents=True, exist_ok=True)コピー先フォルダが存在しない場合、コピー処理は失敗します。
そのため、コピーする前に mkdir() でフォルダを作成しています。
parents=True は途中のフォルダも作る指定です。exist_ok=True は、すでにフォルダがある場合にエラーにしない指定です。
バックアップ処理では毎回同じフォルダを使うことが多いため、この指定がよく使われます。
3. 上書きしにくいファイル名を作ります
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_name = f"{source_path.stem}_{timestamp}{source_path.suffix}"
backup_path = backup_dir / backup_name同じ名前でコピーすると、既存のバックアップを上書きしてしまう可能性があります。
そこで、元のファイル名に日時を付けて保存しています。
source_path.stem は拡張子を除いたファイル名です。source_path.suffix は .txt のような拡張子です。
この2つを使うと、元の名前を残しながら別名のバックアップファイルを作れます。
4. shutil.copy2でコピーします
shutil.copy2(source_path, backup_path)shutil.copy2() は、ファイルの内容に加えて、更新日時などのメタ情報もできるだけコピーします。
単純に内容だけコピーしたい場合は shutil.copy() も使えます。
バックアップ用途では、元ファイルの情報を残したいことがあるため、copy2() を選ぶことが多いです。
ただし、OSやファイルシステムによって、すべての情報が完全に同じになるとは限りません。
実務で使うときのポイント
実務で shutil を使う場面は、バックアップ、成果物の配置、フォルダの複製、処理済みファイルの移動などです。
人が手作業でコピーしている定型作業は、shutil で自動化しやすい候補になります。
ファイルをコピーするときは、上書きの扱いを必ず考えます。
上書きしてよい処理なのか、日時付きで残すべきなのか、同名ファイルがあればエラーにするべきなのかを決めてからコードにすると、後から困りにくくなります。
フォルダごとコピーしたい場合は、shutil.copytree() を使います。
ただし、フォルダ単位のコピーは影響範囲が大きくなりやすいため、コピー元とコピー先を表示してから実行するなど、確認しやすい形にしておくと安心です。