【Python】pathlibでパスを操作する方法|Path・/演算子・glob・read_text

【Python】pathlibでパスを操作する方法|Path・/演算子・glob・read_text Python

ファイルのパスを組み立てたり、拡張子を取り出したり、フォルダ内のファイル一覧を取得したり——こうしたパス操作を、Pythonではpathlibモジュールで行えます。文字列でパスをつなぐ古いやり方やos.pathに比べて直感的で、いまのPythonではこちらが推奨されています。

最大の特徴は、/演算子でパスをつなげることです。Path("dir") / "file.txt"のように書くだけで、WindowsとMac/Linuxのどちらでも正しい区切り文字でパスが組み立てられます。文字列を+でつなぐ必要がなく、区切り文字の違いも自動で吸収してくれます。この記事では、実機のPythonで確認しながら、pathlibの使い方を整理します。

先に結論

  • from pathlib import Pathで読み込み、Path("...")でパスを作ります。
  • パスの結合は/演算子Path("dir") / "file.txt"と書けます。
  • ファイル名は.name、拡張子は.suffix、親フォルダは.parentです。
  • 存在確認は.exists().is_file().is_dir()
  • 読み書きは.read_text(encoding="utf-8").write_text(...)
  • ファイル一覧は.glob("*.txt")、フォルダ作成は.mkdir()です。

実際のファイルの読み書きの基本はファイルの読み書き(with open)、パス文字列の整形は文字列メソッド、文字列との変換は型変換もあわせて参考になります。

スポンサーリンク

Pathオブジェクトを作る

pathlibでは、パスを文字列ではなくPathオブジェクトとして扱います。まずPathを読み込み、パスの文字列を渡して作ります。

path-basic.py
from pathlib import Path

p = Path("data/report.txt")
print(p)          # data\report.txt(Windows)/ data/report.txt(Mac・Linux)
print(type(p))    # <class 'pathlib.WindowsPath'> など

# 文字列に戻したいときは str()
print(str(p))     # パスの文字列

Path("data/report.txt")のように、スラッシュ区切りで書けばどの環境でも動きます。表示するときは、Windowsなら\、Mac・Linuxなら/と、その環境に合った区切り文字に自動で変換されます。文字列が必要な場面ではstr(p)で戻せます。

/演算子でパスを結合する

pathlibの便利さがもっとも出るのが、パスの結合です。Path/演算子を使うだけで、パスをつなげられます。割り算の記号ですが、パスの結合に使われます。

join.py
from pathlib import Path

base = Path("project")

# / でどんどんつなげられる
config = base / "settings" / "config.json"
print(config)   # project\settings\config.json(Windows)

# 文字列の + やスラッシュの付け忘れを気にしなくてよい
# NG例: base + "/settings"  ← 文字列ではないのでエラー
# NG例: "project" + "settings"  ← 区切り文字が抜ける
パスの結合は + ではなく /

実機で確認したところ、Path("project") / "settings" / "config.json"で正しく結合されたパスが得られました。文字列で"project" + "settings"とつなぐと区切り文字が抜けてしまい、"project/" + "settings"のように自分でスラッシュを付けると、今度はWindowsとMac/Linuxの違いに悩まされます。pathlib/演算子なら、区切り文字を自分で書く必要がなく、環境ごとの違いも自動で吸収されます。これがos.path.join()よりも読みやすいとされる理由です。左側がPathであれば、右側は普通の文字列でかまいません。

パスの一部を取り出す name/stem/suffix/parent

パスからファイル名や拡張子、親フォルダを取り出すのも簡単です。.name.stem.suffix.parentといった属性を使います。

parts.py
from pathlib import Path

p = Path("project/data/report.csv")

print(p.name)     # report.csv(ファイル名)
print(p.stem)     # report(拡張子を除いた名前)
print(p.suffix)   # .csv(拡張子・ドット込み)
print(p.parent)   # project\data(親フォルダ)

# 拡張子が複数あるとき stem は最後だけ外す
q = Path("archive.tar.gz")
print(q.stem)     # archive.tar
print(q.suffix)   # .gz

実機でも、Path("project/data/report.csv")からname=report.csvstem=reportsuffix=.csvparent=project/dataが取り出せました。.suffixはドット込み".csv")で返る点に注意します。またarchive.tar.gzのように拡張子が2つある場合、.stemは最後の1つだけを外してarchive.tarになります。拡張子で処理を分けたいときは、if p.suffix == ".csv":のように判定できます。

存在確認 exists/is_file/is_dir

ファイルやフォルダが存在するかは.exists()、ファイルかどうかは.is_file()、フォルダかどうかは.is_dir()で調べられます。読み込む前の確認に使います。

exists.py
from pathlib import Path

p = Path("data/report.txt")

if p.exists():
    print("あります")
else:
    print("ありません")

print(p.is_file())   # ファイルなら True
print(p.is_dir())    # フォルダなら True

# 無いファイルでもエラーにならず False が返る
print(Path("no_such_file.txt").exists())   # False

実機でも、存在するファイルはexists()is_file()True、存在しないパスはexists()Falseになりました。存在しないパスを指定してもエラーにはならず、Falseが返ります。ファイルを開く前にexists()で確認しておくと、FileNotFoundErrorを避けられます。

ファイルを読み書きする read_text/write_text

pathlibでは、with openを使わずに1行でファイルの読み書きができます。読み込みは.read_text()、書き込みは.write_text()です。日本語を扱うならencoding="utf-8"を指定します。

read-write.py
from pathlib import Path

p = Path("memo.txt")

# 書き込み(ファイルが無ければ作成)
p.write_text("こんにちは", encoding="utf-8")

# 読み込み
text = p.read_text(encoding="utf-8")
print(text)   # こんにちは

# バイナリは read_bytes / write_bytes
read_text / write_text も encoding を指定する

実機で確認したところ、write_text("こんにちは", encoding="utf-8")で書き込み、read_text(encoding="utf-8")で読み戻せました。with openと同じく、日本語を扱うときはencoding="utf-8"を指定しないと、Windowsでは文字化けやエラーになりますread_text()はファイル全体を一度に読み込むため手軽ですが、巨大なファイルではwith openで1行ずつ読む方法のほうがメモリを節約できます。用途に応じて使い分けてください。

フォルダを作る mkdir

フォルダの作成は.mkdir()です。途中のフォルダもまとめて作るparents=Trueと、すでにあってもエラーにしないexist_ok=Trueをよく使います。

mkdir.py
from pathlib import Path

# 途中のフォルダもまとめて作る・既にあってもエラーにしない
Path("output/2026/06").mkdir(parents=True, exist_ok=True)

# parents=False(既定)だと、途中のフォルダが無いとエラー
# exist_ok=False(既定)だと、既にあると FileExistsError

実機でも、mkdir(parents=True, exist_ok=True)で複数階層のフォルダをまとめて作成でき、再実行してもエラーになりませんでした。parents=Trueを付けないと途中のフォルダが無いときにエラー、exist_ok=Trueを付けないと既に存在するときにFileExistsErrorになります。出力先フォルダを用意するときの定番の書き方です。

ファイル一覧を取得する glob

フォルダ内のファイル一覧は.glob()で取得します。"*.txt"のようなパターンで、特定の拡張子だけを絞り込めます。

glob.py
from pathlib import Path

folder = Path("data")

# data フォルダ内の .csv ファイル一覧
for f in folder.glob("*.csv"):
    print(f.name)

# サブフォルダも含めて探すなら ** を使う(rglob でも同じ)
for f in folder.glob("**/*.csv"):
    print(f)

# リストにまとめる
csv_files = list(folder.glob("*.csv"))
print(len(csv_files), "個")

実機でも、folder.glob("*.log").logファイルだけを一覧できました。glob()for文で回せるので、見つかったファイルを順に処理できます。サブフォルダも含めて再帰的に探すには"**/*.csv"のように**を使うか、rglob("*.csv")を使います。件数を数えたいときはlist()に変換してlen()で取得します。

カレント・ホームディレクトリ cwd/home

現在の作業フォルダはPath.cwd()、ユーザーのホームフォルダはPath.home()で取得できます。基準となるフォルダを得るのに使います。

cwd.py
from pathlib import Path

print(Path.cwd())    # 現在の作業フォルダ(カレントディレクトリ)
print(Path.home())   # ユーザーのホームフォルダ

# 現在地を基準にファイルを指定
log_path = Path.cwd() / "logs" / "app.log"
print(log_path)

# 相対パスを絶対パスにする
print(Path("data/report.txt").resolve())

実機でも、Path.cwd()で現在の作業フォルダ、Path.home()でホームフォルダの絶対パスが得られました。これらを基準に/でつなげば、環境に依存しないパスを組み立てられます。相対パスを絶対パスに変換したいときは.resolve()を使います。

os.pathとの対応

従来のos.pathを使ったことがある人向けに、対応する書き方をまとめます。pathlibのほうが短く書けます。

やりたいこと os.path(従来) pathlib
パスの結合 os.path.join(a, b) Path(a) / b
ファイル名 os.path.basename(p) p.name
親フォルダ os.path.dirname(p) p.parent
拡張子 os.path.splitext(p)[1] p.suffix
存在確認 os.path.exists(p) p.exists()
フォルダ作成 os.makedirs(p) p.mkdir(parents=True)

よくある失敗

パスを文字列の+で結合する

区切り文字が抜けたり環境差で壊れたりします。Path(a) / bを使います。

read_text/write_textでencodingを省く

Windowsでは文字化けします。encoding="utf-8"を指定します。

suffixにドットが無いと思い込む

.suffixはドット込み(".txt")です。比較はp.suffix == ".txt"とします。

mkdirでparents/exist_okを付けない

途中のフォルダが無い・既にある場合にエラーになります。mkdir(parents=True, exist_ok=True)が安全です。

globの結果を一覧と思って何度も使う

glob()はイテレータを返します。何度も使うならlist()に変換します。

よくある質問

Qパスを結合するには?
APath(a) / bのように/演算子を使います。Path("dir") / "file.txt"で結合でき、区切り文字は環境に合わせて自動で付きます。文字列の+でつなぐと区切り文字が抜けたり環境差で壊れたりするため、/を使うのが安全です。
Qファイル名や拡張子を取り出すには?
Aファイル名はp.name、拡張子を除いた名前はp.stem、拡張子はp.suffix(ドット込み)、親フォルダはp.parentで取り出せます。拡張子で処理を分けるならif p.suffix == ".csv":のように判定します。
Qpathlibとos.pathはどちらを使うべき?
A新しく書くコードではpathlibが推奨されます。/演算子での結合や.name.suffixといった属性により、os.pathよりも短く読みやすく書けます。既存のos.pathのコードと混在する場合も、str(p)で文字列に戻せば連携できます。
Qフォルダ内のファイル一覧を取得するには?
APath("フォルダ").glob("*.txt")で、パターンに合うファイルを取得できます。サブフォルダも含めるならglob("**/*.txt")またはrglob("*.txt")を使います。glob()はイテレータを返すため、何度も使うときはlist()に変換します。
Qpathlibでファイルを読み書きするには?
Ap.write_text("内容", encoding="utf-8")で書き込み、p.read_text(encoding="utf-8")で読み込めます。with openを使わずに1行で書けて手軽です。日本語を扱うときはencoding="utf-8"を必ず指定してください。

まとめ

  • from pathlib import Pathで読み込み、Path("...")でパスを作ります。
  • パスの結合は/演算子。文字列の+は使いません。
  • ファイル名.name、拡張子.suffix(ドット込み)、親.parent
  • 存在確認.exists()、読み書き.read_text()/.write_text()(encoding指定)。
  • 一覧は.glob("*.txt")、フォルダ作成は.mkdir(parents=True, exist_ok=True)

pathlibを使うと、パス操作のコードが短く・安全になります。とくに/演算子でのパス結合は一度使うと手放せません。os.pathや文字列でパスを組み立てていた人も、新しいコードではぜひpathlibを使ってみてください。WindowsとMac/Linuxの違いに悩まされることが、ぐっと減ります。