【Python】pathlibとは?初心者にもわかりやすくファイル操作を解説
はじめに
Pythonでファイルやディレクトリを扱う場面は、プログラミングに慣れてくると意外と頻繁に訪れます。
たとえばログファイルを生成したり、画像をまとめて処理したり、さまざまな状況でファイル操作が必要になるかもしれません。
そこで便利なのが、pathlib という機能です。
pathlibを活用すると、パス文字列を自前で連結したり、動作環境の違い(WindowsとLinuxでのパス区切りの違いなど)を意識したりする負担が減ります。
それだけでなく、ファイルの読み書きやディレクトリの作成も直感的に記述できるようになるのです。
この記事では、Python初心者にもわかりやすい言葉でpathlibについて解説します。
具体的なコード例をいくつか紹介するので、それらを参考にしながら学びを深めてみてください。
この記事を読むとわかること
- Pythonの標準ライブラリであるpathlibの概要
- pathlibを使ったパス(Pathオブジェクト)の生成方法
- パスの結合やファイル操作の具体的な手順
- ディレクトリ操作やファイル検索のコード例
- よく使われるメソッドやプロパティの活用シーン
pathlibとは
Pythonには古くから os.path
や glob
といったモジュールがあり、ファイルのパス操作や探索を行うことができました。
ですが、文字列をベースにパスをくっつけたり、スラッシュなどの区切り文字を意識したりする必要があり、少しわかりにくい部分もありました。
そこで登場したのがpathlibというモジュールです。
pathlibでは、パスを文字列ではなくオブジェクトとして扱います。
このオブジェクトを「Pathオブジェクト」と呼びます。
Pathオブジェクトを使うことで、パスの結合やファイル操作、ディレクトリ操作が直感的になるため、コードを読みやすく書きやすくできます。
pathlibの主なメリット
pathlibを使うと、ファイルパスに関する様々な処理をひとまとめにしやすくなります。
具体的には、以下のようなポイントが挙げられます。
OSによるパス区切り文字の違いを意識せずに済む
Windowsでは \
(バックスラッシュ)、LinuxやmacOSでは /
(スラッシュ)が区切り文字として使われます。
しかしpathlibのPathオブジェクトを使えば、そのあたりを自動的に考慮し、適切に処理してくれます。
メソッドチェーンで直感的にパスを扱える
文字列を単純につなげるのではなく、joinpath()
や演算子 /
を使ってスッキリとコードが書ける点が魅力です。
ファイルの存在チェックや読み書き、ディレクトリ作成がシンプル
パスを表すオブジェクトが、そのままファイル操作やディレクトリ操作にも対応しているのは便利でしょう。
Pathオブジェクトの基本的な生成方法
pathlibを使うときは、まず Path
クラスをインポートします。
以下のようなコードでPathクラスを呼び出し、そこからPathオブジェクトを生成できます。
from pathlib import Path # カレントディレクトリ上のexample.txtというパスを示すPathオブジェクトを生成 p = Path("example.txt") print(p)
実行すると example.txt
という文字列が出力されます。
しかしこれ自体は文字列ではなく、Pathオブジェクトとして扱われている点がポイントです。
さまざまなパスの指定例
Path()
に渡す引数は相対パスや絶対パスだけでなく、ホームディレクトリなどの操作も可能です。
from pathlib import Path # 相対パス rel_path = Path("src") / "data" / "input.csv" print(rel_path) # 絶対パス abs_path = Path("/usr/local/bin/python") print(abs_path) # ホームディレクトリ home_path = Path.home() print(home_path) # カレントディレクトリ cwd_path = Path.cwd() print(cwd_path)
上記のように Path("src") / "data" / "input.csv"
のように書くと、簡単にパスを結合できます。
文字列操作でのパス結合よりも、可読性が高くなるでしょう。
また Path.home()
はユーザーのホームディレクトリパスを返し、Path.cwd()
は現在の作業ディレクトリを返します。
演算子 / と joinpath()
パスを連結するには、先ほどのようにスラッシュ演算子 /
を使う方法と、 joinpath()
を使う方法があります。
両者はほぼ同じ働きをしますが、 /
の方がコードが短くなるので活用しやすいかもしれません。
from pathlib import Path p1 = Path("files").joinpath("images").joinpath("photo.jpg") p2 = Path("files") / "images" / "photo.jpg" print(p1) # files/images/photo.jpg print(p2) # files/images/photo.jpg
どちらも同じ結果を得られますので、好みや可読性で使い分けるとよいでしょう。
Pathオブジェクトの主なプロパティとメソッド
pathlibには多数のメソッドやプロパティが用意されています。
ここでは、よく使われるものをいくつか紹介します。
name, stem, suffix
ファイル名や拡張子を取得したいときは、これらのプロパティが役立ちます。
from pathlib import Path p = Path("files/images/photo.jpg") print(p.name) # photo.jpg print(p.stem) # photo print(p.suffix) # .jpg
- name: ファイル名全体(photo.jpg)
- stem: 拡張子を除いた部分(photo)
- suffix: 拡張子のみ(.jpg)
parent, parts
パスの親ディレクトリや、パス全体の要素を取得する場合は、以下のようにします。
from pathlib import Path p = Path("/usr/local/bin/python") print(p.parent) # /usr/local/bin print(p.parts) # ('/', 'usr', 'local', 'bin', 'python')
- parent: パスの一つ上のディレクトリ
- parts: パスを要素ごとにタプルとして表現したもの
exists(), is_file(), is_dir()
ファイルやディレクトリの存在チェック、またファイルかディレクトリかを判断するためのメソッドです。
from pathlib import Path p = Path("files/images/photo.jpg") if p.exists(): print("存在します。") if p.is_file(): print("これはファイルです。") elif p.is_dir(): print("これはディレクトリです。") else: print("存在しません。")
実際にファイルが存在するかどうかを確認し、ファイルなのかディレクトリなのかを振り分けることがよくあるでしょう。
resolve()
相対パスを絶対パスに変換したいときや、シンボリックリンクを実際のファイルパスに解決したいときに便利です。
from pathlib import Path p = Path("../pathlib-tutorial/sample.txt") print(p.resolve())
上記の例では、相対パス ../pathlib-tutorial/sample.txt
を絶対パスへと変換して出力します。
ファイル操作の基本
pathlibは、ファイルを開いて読み込みや書き込みをするための機能も備えています。
従来の open()
関数を使わなくても、Pathオブジェクトから直接ファイルを開くことが可能です。
もちろん従来どおり open()
関数に文字列を渡す書き方もできますが、pathlibを使っている場合は以下のように書く方がわかりやすいかもしれません。
ファイルへの書き込み
from pathlib import Path p = Path("example.txt") # テキストファイルへ書き込み with p.open(mode="w", encoding="utf-8") as f: f.write("pathlibでファイル操作をしてみる\n") f.write("2行目の内容です\n")
モードを "w"
にすると書き込みモードになります。
encoding="utf-8"
と明示してあげることで、文字化けなどのトラブルを減らせます。
ファイルの読み込み
from pathlib import Path p = Path("example.txt") # テキストファイルを読み込み with p.open(mode="r", encoding="utf-8") as f: for line in f: print(line.strip())
mode="r"
は読み込みモードです。
for line in f:
のようにループを回すことで、一行ずつテキストを表示できます。
ファイルの内容を操作したいとき、line.strip() で改行を削除して扱うのが便利でしょう。
ファイルの追記
ファイルの末尾に新しい行を追加したい場合は、モードを "a"
とします。
from pathlib import Path p = Path("example.txt") with p.open(mode="a", encoding="utf-8") as f: f.write("この行が追加されます\n")
このようにファイル操作をするときも、Pathオブジェクトで書く方がスッキリ感じられます。
ディレクトリ操作
pathlibを使うと、ディレクトリの生成や削除、ディレクトリ内のファイルを一覧取得する操作なども簡単に行えます。
以下では、代表的なディレクトリ操作をいくつか見てみましょう。
ディレクトリの作成
mkdir()
メソッドを使うと、ディレクトリを作成できます。
from pathlib import Path dir_path = Path("new_folder") # ディレクトリを作成 # exist_ok=True を指定すると、すでに同名ディレクトリがあってもエラーになりません dir_path.mkdir(exist_ok=True)
もし複数階層のディレクトリを一気に作りたいときは、 parents=True
を付ければOKです。
from pathlib import Path deep_dir = Path("parent_dir/child_dir") deep_dir.mkdir(parents=True, exist_ok=True)
これで parent_dir/child_dir
のように、親ディレクトリが存在しなくてもまとめて作成してくれます。
ディレクトリの削除
rmdir()
メソッドを使うと、ディレクトリを削除できます。
ただし、この操作は中身が空のディレクトリしか削除できません。
もし中身が入っているディレクトリを丸ごと削除したい場合は、 shutil
モジュールの rmtree()
を使うのが一般的です。
from pathlib import Path dir_path = Path("old_folder") if dir_path.is_dir(): dir_path.rmdir()
このコードは old_folder
が空であれば削除されますが、中にファイルがあるとエラーになるので注意しましょう。
ディレクトリ内のファイル一覧
ディレクトリ配下のファイルやサブディレクトリを一覧として取得したいときは、 iterdir()
を使います。
from pathlib import Path dir_path = Path("files") for item in dir_path.iterdir(): if item.is_file(): print(f"ファイル: {item.name}") elif item.is_dir(): print(f"ディレクトリ: {item.name}")
iterdir()
は生成されたイテレータから、ディレクトリ直下のファイルやディレクトリをPathオブジェクトとして取り出せます。
もし特定の拡張子だけを検索したいときは、次に紹介する glob()
などを利用すると便利です。
ファイル検索や複数ファイルの処理
pathlibには、ファイルの検索や再帰的な検索に活用できるメソッドがあります。
たとえば glob()
や rglob()
を使うと、名前のパターンからファイルを探し出すことができます。
from pathlib import Path # カレントディレクトリ直下にある*.txtファイルを検索 p = Path(".") for txt_file in p.glob("*.txt"): print(txt_file) # カレントディレクトリ以下のすべてのサブディレクトリも含めて*.pyファイルを検索 for py_file in p.rglob("*.py"): print(py_file)
- glob ("*.txt"): カレントディレクトリ直下のみを検索
- rglob ("*.py"): サブディレクトリも含めて再帰的に検索
多くのファイルを一括で処理したいときなどに非常に有用です。
ファイルのコピーや移動、名前変更
pathlib自体にも rename()
などが用意されており、ファイル名の変更や移動ができます。
ただし、コピーは shutil.copy()
のように他のモジュールを使うケースが多いです。
ファイルの名前変更や移動
from pathlib import Path p = Path("old_name.txt") new_p = p.rename("new_name.txt") print(new_p)
rename()
は、同じディレクトリ内でファイル名を変えるだけでなく、パスを変えることもできます。
もし別のディレクトリに移動したいなら、 rename()
の引数にディレクトリを指定すれば移動扱いになります。
ファイルのコピー
コピーだけは、pathlibに直接的なメソッドがないため shutil.copy()
を使うことが多いです。
from pathlib import Path import shutil src = Path("original.txt") dst = Path("backup/original_bak.txt") shutil.copy(src, dst)
ちなみに shutil
ではなく、copy2()
といったメソッドを使う場合もあります。
これは更新時刻やメタデータも一緒にコピーしてくれたりする点が異なるだけで、用途によって使い分けるイメージです。
実務での活用シーン
pathlibは、実務でもさまざまな場面で利用されています。
たとえば、以下のようなシチュエーションを考えてみましょう。
ログファイルを定期的に生成する
ログを格納するディレクトリを事前に用意しなければならない場合もあるかもしれません。
pathlibなら mkdir(parents=True, exist_ok=True)
で生成してからファイルを書き込む、といった流れを容易に記述できます。
画像をまとめて処理する
rglob("*.jpg")
で一括検索して、ファイルごとにサムネイル作成処理を行うなど便利に使えます。
複数のファイルを一括変換する
CSVファイルをExcelファイルに変換して別フォルダに格納する場合など、ファイルパスの結合と操作が連続することが多いでしょう。
このようなときこそ、pathlibの直感的なパス操作が生きてきます。
pathlibは、WindowsやLinuxなど環境が混在するプロジェクトでも統一的にパス操作を扱える便利な仕組みです。環境の違いに左右されづらいため、チーム開発にも向いています。
トラブルシューティングと注意点
OS固有の操作がある場合
pathlibはOSの違いを吸収してくれますが、すべてを吸収できるわけではありません。
たとえば、権限周りの設定(ファイル属性の読み書きなど)は環境によって挙動が異なる部分があります。
また、Windowsでのみ生じるファイル名の制限(予約語や最大パス長など)に引っかかるケースもまれにあります。
そうした場合には、OSに応じた対策が必要になることがあります。
既存のライブラリとの併用
外部ライブラリが str
型のパス指定を前提としている場合、Pathオブジェクトをそのまま渡すとエラーになるかもしれません。
その場合は、str(p)
のように文字列に変換して渡すことで対応します。
from pathlib import Path import some_library # 仮のライブラリ p = Path("data/input.csv") some_library.load_csv(str(p))
pathlibへの対応が進んでいるライブラリなら、Pathオブジェクトをそのまま渡してもOKな場合があります。
セキュリティ上の注意
ファイルパスの構築が不正な形で行われてしまうと、意図しない場所にファイルを書き込んだり読み込んだりするリスクがあります。
特にWebアプリケーションなど、ユーザーから入力を受け取ってファイルパスを生成するような仕組みがある場合は、pathlibの有無にかかわらず注意が必要です。
必要に応じて正規化やバリデーションを行うことが大切です。
ユーザー入力をそのままパスにすると、予期せぬディレクトリにアクセスするリスクがあります。
pathlibのメソッドを使う場合も、あらかじめ入力チェックやディレクトリ制限を考えるようにしてください。
Pythonの標準ライブラリとの使い分け
pathlibが登場する以前から存在する os
, os.path
, glob
などのモジュールは今でも広く使われています。
もし既存のプロジェクトがそれらで書かれている場合は、無理にpathlibに変えようとすると混乱を招くこともあるかもしれません。
ですが、新規プロジェクトではpathlibの利用が推奨される傾向があります。
理由はコードが読みやすく保守しやすいからです。
少しずつpathlibへの移行を進めたり、新しく書く部分だけpathlibを使ったりするとよいかもしれません。
よく使われるメソッドまとめ
最後に、pathlibでよく使われるメソッド・プロパティを一覧的にまとめておきます。
メソッド/プロパティ | 概要 |
---|---|
joinpath() | パスを結合する |
/ 演算子 | パス結合の演算子 |
is_file() | ファイルかどうかを判断 |
is_dir() | ディレクトリかどうかを判断 |
exists() | パスが実際に存在するかをチェック |
mkdir() | ディレクトリを作成する |
rmdir() | 空のディレクトリを削除する |
iterdir() | ディレクトリの中身を列挙する |
glob() /rglob() | パターンにマッチするファイルを検索 |
resolve() | 相対パスやシンボリックリンクを解決し、絶対パスを取得 |
rename() | パスの名前変更、または移動 |
open() | ファイルを開いて読み書きする |
stem | 拡張子を除いたファイル名 |
suffix | ファイルの拡張子 |
name | ファイル名(拡張子込み) |
parent | 親ディレクトリ |
parts | パスを要素ごとに分割し、タプルで取得 |
cwd() | カレントディレクトリを取得(クラスメソッド) |
home() | ホームディレクトリを取得(クラスメソッド) |
これらを押さえておけば、pathlibの基本的な活用方法はひととおりマスターしたといえます。
まとめ
ここまで、Pythonのpathlibについてかなり詳しく解説してきました。
pathlibの大きな特徴は、文字列操作に頼らず、パスをオブジェクトとして扱えるところです。
その結果、コードの可読性や保守性が高まり、初心者でも理解しやすく書きやすいというメリットがあります。
実際の開発でも、画像やテキストファイルの処理をまとめて行う時などに非常に便利です。
ファイルの存在チェックや読み書き、ディレクトリの生成や削除など幅広い操作をまとめて行えるのも頼もしいポイントです。
もしこれまで os.path
や文字列操作を使っていた方は、この機会にpathlibを使ってみてはいかがでしょうか。
きっと、Pythonでのファイル処理がより直感的になるはずです。