Python | ファイル操作など:pathlib.Path

Python
スポンサーリンク

概要(pathlib.Path は「パスを文字列ではなくオブジェクトで扱う」現代的なやり方)

pathlib は標準ライブラリで、ファイルやフォルダの“パス”を Path オブジェクトとして安全・直感的に扱えます。文字列連結や OS ごとの区切り文字(/ と \)に悩まず、メソッドで存在確認・作成・削除・読み書きまで一気通貫で書けるのが強みです。

from pathlib import Path

p = Path("data") / "sample.txt"  # 「/」で自然に結合
print(p.exists(), p.parent, p.name, p.suffix)  # True/False, 親フォルダ, ファイル名, 拡張子
Python

基本の考え方(ここが重要)

文字列ではなく「Path オブジェクト」にしてから操作する

Path は「そのパスを表すオブジェクト」です。結合・分解・移動・読み書きなどをメソッドで記述できます。まず Path にしてから扱うことで、コードの安全性と読みやすさが段違いに上がります。

from pathlib import Path

p = Path("logs") / "app.log"
print(p.parent)  # logs(親ディレクトリ)
print(p.stem)    # app(拡張子を除いた名前)
print(p.suffix)  # .log(拡張子)
Python

OS 差を気にせず書ける(区切り文字やホームディレクトリ)

Path は OS に応じて区切り文字を自動で扱います。ホームディレクトリの展開や絶対パス化も簡単です。

from pathlib import Path

home = Path.home()                   # 例: /Users/you や C:\Users\you
p = Path("~/data").expanduser()     # ~ をホームに展開
abs_p = p.resolve()                  # 絶対パスへ(実体に基づく解決)
Python

よく使う操作(存在確認・作成・列挙・読み書き)

存在確認・種別判定(ファイルかディレクトリか)

from pathlib import Path

p = Path("data/sample.txt")
print(p.exists())   # True/False
print(p.is_file())  # ファイルか
print(p.is_dir())   # ディレクトリか
Python

ディレクトリ作成・ファイル作成・削除

from pathlib import Path

d = Path("output/reports")
d.mkdir(parents=True, exist_ok=True)  # 親ごと作成、既存ならスキップ

f = d / "today.txt"
f.touch(exist_ok=True)                # 空ファイル作成(既存ならスキップ)
f.unlink(missing_ok=True)             # ファイル削除(無ければスキップ)
Python

ファイル一覧・パターンマッチ(glob / rglob)

from pathlib import Path

for p in Path("data").glob("*.csv"):     # data直下のCSV
    print(p)

for p in Path("data").rglob("**/*.json"):  # 再帰的にサブフォルダも
    print(p)
Python

読み書きのショートカット(read_text / write_text / read_bytes / write_bytes)

open を毎回書かず、テキストやバイナリを一発で扱えます。エンコーディングは明示が基本です。

from pathlib import Path

p = Path("data/message.txt")
p.write_text("こんにちは\n", encoding="utf-8")
text = p.read_text(encoding="utf-8")
Python

移動・コピー・リネーム(rename / replace)

from pathlib import Path

p = Path("data/old.txt")
p.rename("data/new.txt")   # 名前変更(既存上書きは失敗しうる)
p.replace("data/new.txt")  # 置換(上書き込み可、atomic に近い挙動)
Python

文字列との橋渡し(既存 API と一緒に使う)

文字列が必要なら str(…)、Path を渡せる場面も多い

多くの標準ライブラリは Path をそのまま受け付けますが、必要なら str にすれば従来の API に渡せます。

from pathlib import Path
import csv

p = Path("data/items.csv")
with p.open("r", encoding="utf-8", newline="") as f:  # Path.open は open() と同等
    reader = csv.reader(f)
    for row in reader:
        print(row)

# 文字列にしたいとき
path_str = str(p)
Python

実務での設計ポイント(深掘り)

「Path を最初に作る」習慣で安全性を高める

パス文字列の連結は罠が多い(区切り忘れ・重複・OS差)。最初に Path を作り「/」で結合、存在確認・作成はメソッドで。これだけでバグが激減します。

ルート基準で「絶対インポート」的に扱う

プロジェクトのルート Path を 1 つ作り、そこから相対で辿ると全コードの見通しが良くなります。テストでもパスが安定します。

from pathlib import Path

ROOT = Path(__file__).resolve().parent  # このファイルの場所を基準に
DATA = ROOT / "data"
CONFIG = ROOT / "config" / "settings.json"
Python

例外や競合を想定した“安全な書き込み”(テンポラリ→置き換え)

重要ファイルはテンポラリに書いてから置き換え。クラッシュ時でも中途半端な内容が露出しません。

import os
from pathlib import Path

def atomic_write(path: Path, data: str) -> None:
    tmp = path.with_suffix(path.suffix + ".tmp")
    tmp.write_text(data, encoding="utf-8")
    os.replace(tmp, path)  # 原子的な置き換え
Python

例題で身につける(定番から一歩先まで)

例題1:CSV を列挙して合計を出す

from pathlib import Path
import csv

def total_qty(data_dir: str) -> int:
    total = 0
    for p in Path(data_dir).glob("*.csv"):
        with p.open("r", encoding="utf-8", newline="") as f:
            for name, qty in csv.reader(f):
                total += int(qty)
    return total

print(total_qty("data"))
Python

例題2:ログを日付フォルダにローテーション保存

from pathlib import Path
from datetime import date

def save_log(msg: str) -> None:
    root = Path("logs") / date.today().isoformat()
    root.mkdir(parents=True, exist_ok=True)
    f = root / "app.log"
    with f.open("a", encoding="utf-8", newline="\n") as out:
        out.write(msg + "\n")

save_log("started")
Python

例題3:JSON を読み込み、正規化して別フォルダへ出力

from pathlib import Path
import json

def normalize(src: Path, dst: Path) -> None:
    data = src.read_text(encoding="utf-8")
    obj = json.loads(data)
    dst.parent.mkdir(parents=True, exist_ok=True)
    dst.write_text(json.dumps(obj, ensure_ascii=False, indent=2, sort_keys=True),
                   encoding="utf-8")

normalize(Path("data/raw.json"), Path("output/normalized.json"))
Python

例題4:拡張子ごとに振り分けて移動

from pathlib import Path

def sort_by_ext(src_dir: str) -> None:
    base = Path(src_dir)
    for p in base.iterdir():
        if p.is_file():
            target = base / p.suffix.lstrip(".")  # 例: ".png" → "png"
            target.mkdir(exist_ok=True)
            p.replace(target / p.name)

sort_by_ext("downloads")
Python

まとめ

pathlib.Path は「パスをオブジェクトとして扱い、OS 差を気にせず直感的に操作する」ための標準手段です。結合は「/」、存在確認・作成・列挙・読み書きはメソッドで一貫、必要なら read_text/write_text のショートカットで簡潔に。プロジェクトのルート Path を基準に構成し、重要な書き込みは原子的に。まず“文字列でパスを組むのをやめて Path にする”——この一歩で、初心者のファイル操作は読みやすく、堅牢で、実務品質に一気に近づきます。

タイトルとURLをコピーしました