ファイルのパスを組み立てたり、拡張子を取り出したり、フォルダ内のファイル一覧を取得したり——こうしたパス操作を、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を読み込み、パスの文字列を渡して作ります。
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に/演算子を使うだけで、パスをつなげられます。割り算の記号ですが、パスの結合に使われます。
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といった属性を使います。
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.csv、stem=report、suffix=.csv、parent=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()で調べられます。読み込む前の確認に使います。
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"を指定します。
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
実機で確認したところ、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をよく使います。
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"のようなパターンで、特定の拡張子だけを絞り込めます。
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()で取得できます。基準となるフォルダを得るのに使います。
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()に変換します。
よくある質問
Path(a) / bのように/演算子を使います。Path("dir") / "file.txt"で結合でき、区切り文字は環境に合わせて自動で付きます。文字列の+でつなぐと区切り文字が抜けたり環境差で壊れたりするため、/を使うのが安全です。p.name、拡張子を除いた名前はp.stem、拡張子はp.suffix(ドット込み)、親フォルダはp.parentで取り出せます。拡張子で処理を分けるならif p.suffix == ".csv":のように判定します。pathlibが推奨されます。/演算子での結合や.name・.suffixといった属性により、os.pathよりも短く読みやすく書けます。既存のos.pathのコードと混在する場合も、str(p)で文字列に戻せば連携できます。Path("フォルダ").glob("*.txt")で、パターンに合うファイルを取得できます。サブフォルダも含めるならglob("**/*.txt")またはrglob("*.txt")を使います。glob()はイテレータを返すため、何度も使うときはlist()に変換します。p.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の違いに悩まされることが、ぐっと減ります。

