概要
Python の新しいファイルパス操作モジュール pathlib の使い方について解説します。
pathlib は Python 3.6 で導入されたファイルパス操作モジュールです。これまでの os.path モジュールに比べて、簡潔にコードが書けるので、Python 3.6 以上であれば、こちらを使用することをおすすめします。
os.path と pathlib
機能的にはどちらも同じことができますが、os.path はファイルパスを表す文字列を扱うのに対し、pathlib はファイルパスをオブジェクト化して扱うという違いがあります。実際の例を見てみましょう。
下記のようなディレクトリ構造があり、A/a.png があるディレクトリを基点に、B/b.png を相対的に指定するコードを考えます。
├── A
│ └── a.png
└── B
└── b.png
import os
from pathlib import Path
path = "A/a.png"
# os.path
dst_path = os.path.join(os.path.dirname(os.path.dirname(path)), "B/b.png")
print(dst_path)
# pathlib
dst_path = Path(path).parent.parent / "B/b.png"
print(dst_path)
os.path と比較して、pathlib は簡潔なコードになっていることがわかります。
ファイルの結合
pathlib の一番の特徴はファイルの結合をディレクトリの区切り文字と同じフォワードスラッシュ / で行えることでしょう。
from pathlib import Path
path = Path("/hoge")
img_path = path / "fuga" / "sample.jpg"
print(img_path) # /hoge/fuga/sample.jpg
ファイル名や親ディレクトリの取得
パスからファイル名や親ディレクトリなどを取得する方法について紹介します。
| Windows | Linux | ||
|---|---|---|---|
| 概要 | パス | C:\data\hoge\sample.tar.gz | /data/hoge/sample.tar.gz |
| パスの構成要素 | Path.parts | (‘C:\’, ‘data’, ‘hoge’, ‘sample.tar.gz’) | (‘/’, ‘data’, ‘hoge’, ‘sample.tar.gz’) |
| ドライブレター | Path.drive | C: | |
| ルート | Path.root | \ | / |
| ドライブレター付きのルート | Path.anchor | C:\ | |
| 親ディレクトリの一覧 | Path.parents | [‘C:/data/hoge’, ‘C:/data’, ‘C:/’] | [‘/data/hoge’, ‘/data’, ‘/’] |
| 1つ上の階層 | Path.parents[0] | C:\data\hoge | /data/hoge |
| 2つ上の階層 | Path.parents[1] | C:\data | /data |
| 1つ上の階層 | Path.parent | C:\data\hoge | /data/hoge |
| ファイル名 | Path.name | sample.tar.gz | sample.tar.gz |
| 拡張子を除いたファイル名 | Path.stem | sample.tar | sample.tar |
| 拡張子 | Path.suffix | .gz | .gz |
| 拡張子の一覧 | Path.suffixes | [‘.tar’, ‘.gz’] | [‘.tar’, ‘.gz’] |
| ファイル URI で表したパス | Path.as_uri() | file:///C:/data/hoge/sample.tar.gz | file:///data/hoge/sample.tar.gz |
| \ を / に置き換えたパス | Path.as_posix() | :/data/hoge/sample.tar.gz |
Windows
from pathlib import Path
path = Path(r"C:\data\hoge\sample.tar.gz")
# パスを分解する
print(path.parts) # ('C:\\', 'data', 'hoge', 'sample.tar.gz')
# ドライブレターを取得 (Windows)
print(path.drive) # C:
# ルートを取得
print(path.root) # \
# ドライブレターとルートを結合した文字を取得 (Windows)
print(path.anchor) # C:\
# 親ディレクトリの一覧
print([x for x in path.parents])
# [WindowsPath('C:/data/hoge'), WindowsPath('C:/data'), WindowsPath('C:/')]
# 1つ上の階層
print(path.parents[0]) # C:\data\hoge
# 2つ上の階層
print(path.parents[1]) # C:\data
# 1つ上の階層
print(path.parent) # C:\data\hoge
# ファイル名
print(path.name) # sample.tar.gz
# 拡張子を除いたファイル名
print(path.stem) # sample.tar
# 拡張子
print(path.suffix) # .gz
# 拡張子の一覧
print(path.suffixes) # ['.tar', '.gz']
# ファイル URI で表したパス
print(path.as_uri()) # file:///C:/data/hoge/sample.tar.gz
# バックスラッシュ \ をフォワードスラッシュ / に置き換えたパス (Windows)
print(path.as_posix()) # :/data/hoge/sample.tar.gz
Unix
from pathlib import Path
path = Path(r"/data/hoge/sample.tar.gz")
# パスを分解する
print(path.parts) # ('/', 'data', 'hoge', 'sample.tar.gz')
# ルートを取得
print(path.root) # /
# 親ディレクトリの一覧
print([x for x in path.parents])
# [PosixPath('/data/hoge'), PosixPath('/data'), PosixPath('/')]
# 1つ上の階層
print(path.parents[0]) # /data/hoge
# 2つ上の階層
print(path.parents[1]) # /data
# 1つ上の階層
print(path.parent) # /data/hoge
# ファイル名
print(path.name) # sample.tar.gz
# 拡張子を除いたファイル名
print(path.stem) # sample.tar
# 拡張子
print(path.suffix) # .gz
# 拡張子の一覧
print(path.suffixes) # ['.tar', '.gz']
# ファイル URI で表したパス
print(path.as_uri()) # file:///data/hoge/sample.tar.gz
ファイルの存在確認
| 概要 | パス | 備考 |
|---|---|---|
| ファイルが存在するかどうか | Path.exists() | |
| ディレクトリかどうか | Path.is_dir() | |
| ファイルかどうか | Path.is_file() | |
| マウントポイントかどうか | Path.is_mount() | Unix のみ |
| シンボリックリンクかどうか | Path.is_symlink() | |
| Unix ソケットかどうか | Path.is_socket() | Unix のみ |
| ファイルが空かどうか | Path.stat().st_size == 0 | |
| 絶対パスかどうか | Path.is_absolute() | |
| パスが other を基点とした相対パスかどうかを判定する | PurePath.is_relative_to(*other) | |
| 2つのパスが同じ場所を指すかどうか | Path.samefile(other_path) |
ファイルサイズ、所有ユーザー、所有グループを取得する
以下の関数でファイルサイズ、所有ユーザー、所有グループを取得できます。
from pathlib import Path
path = Path("sample.jpg")
# ファイルサイズ
print(path.stat().st_size) # 18122
# ファイルが空かどうか
print(path.stat().st_size == 0) # False
# ファイルの所有ユーザー
print(path.owner()) # root
# ファイルの所有グループ
print(path.group()) # root
パスの書き換え置き換える
以下の関数でパスからファイル名のファイル名、拡張子を除いたファイル名、拡張子だけを置き換えられます。
from pathlib import Path
path = Path("hoge/sample.png")
# ファイル名を置き換える
print(path.with_name("fuga.txt")) # hoge/fuga.txt
# 拡張子を除いたファイル名を置き換える
print(path.with_stem("fuga")) # hoge/fuga.txt
# 拡張子を除いたファイル名を置き換える
print(path.with_suffix(".jpg")) # hoge/sample.jpg
# 絶対パスに変換する。
print(path.resolve()) # /data/notebook/pystyle/python/python-pathlib/hoge/sample.png
# シンボリックリンクが指す先を取得する
path = Path("hoge/samples")
print(path.readlink()) # /data/samples
カレントディレクトリ、ホームディレクトリを取得する
| 概要 | ||
|---|---|---|
| カレントディレクトリ | Path.cwd() | |
| ホームディレクトリ | Path.home() | |
| ホームディレクトリを表す ~ を展開する | Path.expanduser() |
# ホームディレクトリを取得する
print(Path.home()) # /root
# カレントディレクトリを取得する
print(Path.cwd()) # /data/notebook/pystyle/python/python-pathlib
# ホームディレクトリを表す ~ を展開する
path = Path("~/sample")
print(path.expanduser()) # /root/sample
権限の変更、ファイル/ディレクトリの作成、削除
mkdir() でディレクトリを作成します。
- 権限は
modeで指定します。ox666のように8進数で指定するとよいでしょう。 parents=Trueを指定すると、親ディレクトリが存在しない場合はそれも作成します。- ディレクトリがすでに存在する場合はデフォルトではエラーになりますが、
exist_ok=Trueを指定すると、ディレクトリが存在しない場合のみ作成します。
# ディレクトリを作成する。
path = Path("output")
path.mkdir(mode=0o777, parents=True, exist_ok=True)
rmdir() で空のディレクトリを削除できます。
path = Path("output")
path.rmdir()
中身があるディレクトリでファイルごと削除する場合は shutil.rmtree() を使用します。
権限の変更は chmod() でできます。
# 権限を変更する。
path = Path("sample.py")
path.chmod(0o666)
touch() で空のファイルを作成します。
- 権限は
modeで指定します。ox666のように8進数で指定するとよいでしょう。 - ファイルがすでに存在する場合はデフォルトではエラーになりますが、
exist_ok=Trueを指定すると、ファイルが存在しない場合のみ作成します。
## ファイルを作成する。
path = Path("sample.txt")
path.touch(mode=0o666, exist_ok=True)
unlink() でファイルを削除します。
- ファイルが存在しない場合はデフォルトではエラーになりますが、missing_ok=True を指定すると、ファイルが存在する場合のみ削除します。
# ファイルを削除する。
path = Path("sample.txt")
path.unlink(missing_ok=True)
write_bytes() でバイナリデータ、write_text() でテキストデータをファイルを開いて書き込めます。
# ファイルを開いて、バイナリデータを書き込む
path = Path("sample.bin")
path.write_bytes(b"Binary file contents")
# ファイルを開いて、バイナリデータを書き込む
path = Path("sample.txt")
path.write_text("Binary file contents")
symlink_to(target) で target へのシンボリックリンクを作成します。
Windows の場合、リンク先がディレクトリの場合 symlink_to(target, target_is_directory=True) とする必要があります。
# シンボリックリンクを作成する。
path = Path("samples")
path.symlink_to("/data/samples")
ファイルを読み込む
Path.read_bytes() で指定したファイルをバイナリモード、Path.read_text() でテキストモードで読み込み、返します。
Path.open() で組み込み関数 open() と同様のファイルオープン処理が行えます。
path = Path("sample.bin")
print(path.read_bytes())
path = Path("sample.txt")
print(path.read_text())
path = Path("sample.txt")
f = path.open()
print(f.read())
ファイルを移動する、リネームする
Path.rename() でリネーム処理が行えます。
src = Path("sample.bin")
dst = Path("hoge.bin")
src.rename(dst)
ファイル一覧を取得する
Path.iterdir() でディレクトリ内のファイル一覧を取得できます。
Path.glob() で glob.glob() と同様、ワイルドカードを使ったより高度な検索が行えます。glob() で検索する場合、入れ子になったディレクトリも再帰的に検索する場合はその部分を ** にします。
path = Path("/data")
for p in path.iterdir():
print(p)
print()
for p in path.glob("*.zip"):
print(p)
print()
for p in path.glob("**/*.jpg"): # または path.rglob("*.jpg")
print(p)
print()

コメント