順番に読み進めながら学べます

shutil と tempfile — ファイル一括操作と一時ファイル

shutil.copy/move/rmtreeでファイルとフォルダを一括操作し、tempfile.NamedTemporaryFileのdelete切り替えと一時ファイル経由のアトミック書き込みを、実行しながら学びます。

ファイルとフォルダを丸ごと操作する shutilと、使い捨ての一時ファイルを扱うtempfileの 2 つを整理します。shutil.copy / move / rmtreeによるファイル一括操作、NamedTemporaryFileの安全な使い方、両者を組み合わせたアトミック書き込みパターンまで扱います。

shutil — ファイルとフォルダの操作を 1 行で書く

shutilshell utilitiesの略で、シェル(コマンドライン)でcp / mv / rm -rのように使う操作をPython のコードから 1 行で呼び出せる標準ライブラリです。osモジュールにもos.renameなどはありますが、shutil再帰的なフォルダコピーツリー削除といった、よりまとまった単位の操作を提供します。

shutil の主要関数 3 種類
shutil.copy(src, dst)複製を作るshutil.move(src, dst)移動 or 改名shutil.rmtree(path)再帰的に削除
copyはファイルを別の場所に複製、moveは移動(または同じ場所での名前変更)、rmtreeはフォルダごと再帰的に削除。3 つを覚えるだけで日常の運用処理はほぼカバーできる。
関数動作備考
shutil.copy(src, dst)ファイルを複製するdst がフォルダなら同名でその中に作る
shutil.copy2(src, dst)copy + 更新日時などのメタ情報も保持バックアップ用途に向く
shutil.copytree(src, dst)フォルダごと再帰的に複製するdst は存在してはいけない
shutil.move(src, dst)ファイルやフォルダを移動・名前変更する同じパス上なら rename と等価
shutil.rmtree(path)フォルダと配下を再帰的に削除する戻せない。実行前に対象パスをよく確認する
import shutil
import os

# 1) ファイルを別の場所にコピー (バックアップを作る典型例)
os.makedirs("backups", exist_ok=True)        # コピー先のフォルダを用意
shutil.copy("data/sales.csv", "backups/sales_2024.csv")

shutil.move("logs/temp.log", "logs/archive_2024.log")

shutil.rmtree("old_data")

rmtree は取り消せない

shutil.rmtree(path)path配下を物理削除します。Python では「ゴミ箱」を経由せず、即座に消えます。実プロジェクトで使うときは消す対象を print で確認する、if path.startswith("/tmp") のようなガードを入れるなど、人間と機械の両方で守る慣習を付けましょう。

売上 CSV data/sales.csvbackups/sales_backup.csvとしてバックアップします。左の 📂 ファイルから元の中身が確認できます。

① shutil と os を読み込んでください

② コピー先フォルダbackups/を準備してください(既に存在してもエラーにしない方法で)

③ ファイルを指定の名前でコピーしてください

④ バックアップ先と元ファイル両方の存在をバックアップ完了: True / 元ファイルもある: Trueの形で表示して確認してください

(正しく実行できれば解説が表示されます)

Python エディタ

コードを実行してください

tempfile — 安全に使い捨てファイルを作る

tempfile使い終わったら自動で消える一時ファイルを作るための標準ライブラリです。中間結果の保存・大量データの一時バッファ・テストの作業フォルダなど、「処理中だけ存在すれば良いファイル」のために使います。

手でtmp_xxx.txtのようなファイル名を考えると他のプロセスとぶつかったり消し忘れたりしがちですが、tempfileOS の一時フォルダ重複しないファイル名で作り、処理が終わったら自動で消してくれます。

NamedTemporaryFile のライフサイクル
with NamedTemporaryFile():→ 一時ファイル作成ブロック内で書き込み・読み出しブロックを抜ける→ 自動削除後始末を意識せず安全に使える
withブロックに入った瞬間にファイルが作られ、ブロックを抜けるときに自動で削除される。ファイル名はその場で衝突しない名前が割り当てられるので、自分で命名する必要がない。
関数・属性意味備考
tempfile.NamedTemporaryFilewith で開閉する一時ファイルdelete=False で抜けても残す
tempfile.mkdtemp()一時フォルダのパスを返す削除は自分で shutil.rmtree
tempfile.gettempdir()OS の一時フォルダのパスを返すLinux なら /tmp、macOS は別パス
tf.name実ファイルパス(ランダム名)with の中で参照できる
tf.write / tf.readファイルオブジェクトと同じ APImode 引数で 'w' / 'r' / 'w+' を選ぶ
import tempfile
import os

# with で安全に作って自動削除
with tempfile.NamedTemporaryFile(mode="w+", suffix=".txt", delete=True) as tf:
    tf.write("集計結果の中間データ\n")
    tf.seek(0)
    print("中身:", tf.read())
    print("パス:", tf.name)
# ← ここでブロックを抜けて自動削除される

delete=False と with を組み合わせる場面

書いてから別の場所で読み戻したいときはdelete=Falseを指定して、withを抜けてもファイルが残るようにします。残したファイルは使い終わったら自分で os.remove(path) するか、後述のアトミック書き込みのようにshutil.moveで本来の保存先に置き換えます。

一時ファイルを作って書き込み、削除前と削除後の存在をそれぞれチェックします。delete=FalseNamedTemporaryFileで一時ファイルを作り、書き込み → 読み戻し → 削除前の存在確認 → 削除 → 削除後の存在確認、という流れを試します。

① tempfile と os を読み込んでください

NamedTemporaryFile(mode="w", delete=False)で一時ファイルを開き、sales total: 3750という文字列を書き込んで、tf.nameをパス変数に控えてからwithブロックを抜けてください

os.path.exists(パス)削除前の存在: ◯◯の形で存在を表示してください

os.unlink(パス)でファイルを削除してください

⑤ もう一度os.path.exists(パス)削除後の存在: ◯◯の形で存在を表示してください

Python エディタ

コードを実行してください

`delete=True`で自動削除される一時ファイル

重要な設定ファイルや状態ファイルを直接open("settings.json", "w")で書き換えると、書き込み途中でプロセスが落ちたときにファイルが半分書かれた状態で残ってしまい、次回読み込み時にパースエラーになります。これを避ける定石が「一時ファイルに書ききってから、本来の場所に rename / move する」というアトミック書き込み(atomic、途中で中断されても「完了したか / していないか」しか観測できない更新方式)パターンです。

アトミック書き込みの流れ
直接 open("w")途中で落ちる壊れたファイルが残るtempfile に書き切るshutil.move で本物のパスへ外から見ると一瞬で切り替わる壊れた状態は見えない
直接書きだと途中で落ちると壊れたファイルが残るが、一時ファイル経由だと書き終わった瞬間にだけ本物のパスに切り替わるので、「壊れた状態」が一切見えない
import tempfile
import shutil
import json

final_path = "settings.json"
new_settings = {"theme": "dark", "lang": "ja", "fontSize": 14}

# 1) 一時ファイルに書き切る
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".json") as tf:
    json.dump(new_settings, tf)
    temp_path = tf.name

# 2) 完了したら本物のパスに移動 (この瞬間だけが「切り替わり」のタイミング)
shutil.move(temp_path, final_path)

# 3) 確認
with open(final_path) as f:
    print(json.load(f))
# → {'theme': 'dark', 'lang': 'ja', 'fontSize': 14}

ファイルオブジェクトには「現在の読み書き位置(カーソル)」があり、tf.write(...)を呼ぶとカーソルは書いた直後の位置(= 末尾)に移動します。そのままtf.read()を呼ぶとカーソルから後ろに何も無いため空文字が返るので、tf.seek(0)でカーソルを先頭に戻してから読み直す、というのが定石です。

ファイルカーソルと seek(0) の動き
write("config: ok")カーソルは末尾へread()→ ""(空文字)seek(0)カーソルを先頭へread()→ "config: ok"
write でカーソルが末尾へ進む → そのまま read すると空文字が返る → seek(0) で先頭に戻す → read で書いた内容が取れる。

mode="w+" は読み書き両用のモード

mode="w+"書き込みと読み込みを同じファイルハンドルで両方できるモードです。"w"だけだと書き込み専用でread()が使えず、"r"だけだと読み込み専用でwrite()が使えません。書いてすぐ読み戻す演習では"w+"が必須になります。

with NamedTemporaryFile(delete=True)で一時ファイルを作って自動削除を確認します。withブロックの中で書き込んで読み戻し、ブロックを抜けた後に存在チェックをするとFalseになることを確認します。

① tempfile と os を読み込んでください

tempfile.NamedTemporaryFile(mode="w+", delete=True)with文で開いてください(mode="w+"は読み書き両用)

③ ブロック内でtf.write("config: ok\n")のように書き込み、tf.seek(0)でカーソルを先頭に戻してからtf.read()で読み戻し、中身: ◯◯の形で表示してください

④ ブロック内でパスをsaved_path = tf.nameとして控えてください

⑤ ブロックを抜けた後、os.path.exists(saved_path)の結果をwith 後の存在: ◯◯の形で表示してください(Falseになるはずです)

Python エディタ

コードを実行してください
QUIZ

理解度チェック

まずは1問ずつ答えてみましょう。

Q1次のうち、フォルダごと再帰的に削除したいときに使うのはどれですか?

Q2tempfile.NamedTemporaryFiledelete=False 付きで使う典型的な理由として正しいのはどれですか?

Q3アトミック書き込みの本質は次のうちどれですか?