Pythonでディレクトリ直下の全ファイル/ディレクトリを一覧したい(子も孫もひ孫も...)
#Python
Python 3.5以上だと以下のpathlibの.rglob()が使える。
code:py
import pathlib
# 以下がgeneratorが返ってくる。
# (走査対象のディレクトリは"."になっているが他のでもOK)
paths = pathlib.Path(".").rglob("*")
# 出力してみる。
print(p for p in paths)
# 以下は出力例。
# => PosixPath('test.txt'), PosixPath('dir1'), PosixPath('dir1/dir1-1'), PosixPath('dir1/hello.txt'), PosixPath('dir1/dir1-1/world.txt')
参考: python - How to use glob() to find files recursively? - Stack Overflow
pathlib.Path(...).rglob(...)はgeneratorを返してくれる。上記ではすぐに出力のためにリストにしている。
PosixPathを文字列に変換する
PosixPathを文字列表現にしたい時。
公式「pathlib — Object-oriented filesystem paths — Python 3.8.0 documentation」を見ている感じだとPosixPathを文字列に変換するのは単純にstr()で包む様子。
The string representation of a path is the raw filesystem path itself (in native form, e.g. with backslashes under Windows), which you can pass to any function taking a file path as a string:
上記は引用文で、サンプルコードではWindowsだとパスが適切にバックスラッシュになったりしてくれる様子がデモされている。
ファイルだけやディレクトリだけにフィルタしたい時
Path.is_file()やPath.is_dir()メソッドが使える。
公式: pathlib — Object-oriented filesystem paths — Python 3.8.0 documentation
昔からあるos.path系が良いなら、ファイルやディレクトリでフィルタしたければos.path.isfile(path)やos.path.isdir()も使える。
感想とか
glob.glob()より良いと思ったのはpathlib.Path()の引数に好きなディレクトリを指定できる点。
glob.glob()でもできるが**とか*とうまく文字列を合成しないと予期せぬ結果を招きそうで慎重になる必要があると思っていた点が解消されそう。
os.chdir()を使う方法もあるけど、戻し忘れや並行/並列処理が絡むと厄介なことになったりするのをRubyかNode.jsかで経験したのでこの方法でも解消できると思っていなかった。
globでやりたい時
glob.glob()でやりたければ、以下を使うことも可能。
glob.glob("**", recursive=True)