普段は、DBに格納された扱いやすいデータや1ファイルにまとめられたデータばかり扱っていて、
散らばったファイルからデータを拾ってくることは少ない恵まれた環境で仕事しています。
しかし、久々にあるフォルダ配下に散ってるファイルを再帰的に探してまとめて処理する機会があったのでそのメモです。
以前、特定のフォルダの直下のファイルは、 globで手軽に見つけられるという記事を書きました。
参考: globで手軽にファイル名の一覧を取得する
今回は pathlib を紹介しようと思っていたのですが、
よく globのドキュメントを見ると、 バージョン 3.5 から、再帰的なglobが実装されていたんですね。
参考: glob — Unix 形式のパス名のパターン展開
ということでこちらを使ってみます。
recursive に True を指定し、 pathname の中に ** を含めればいいようです。
拡張子付きのファイルパスだけリストアップするには次のように書きます。
import glob
for f in glob.glob("./**/*.*", recursive=True):
print(f)
"""
./001.txt
./folder01/002.txt
./folder01/003.sql
./folder01/subfolder011/004.txt
./folder01/subfolder011/005.sql
./folder02/006.png
./folder02/subfolder021/007.gif
"""
recursive=False (デフォルト) の場合と一応比較しておきましょう。
for f in glob.glob("./**/*.*", recursive=False):
print(f)
"""
./folder01/002.txt
./folder01/003.sql
./folder02/006.png
"""
for f in glob.glob("./*/*.*", recursive=False):
print(f)
"""
./folder01/002.txt
./folder01/003.sql
./folder02/006.png
"""
比較用に ** を * に変えたものも一緒に載せましたが、
recursive=False の場合は、 ** は * と同じ挙動しかしていないことがわかります。
recursive=True にすると、 ** は複数階層のフォルダ(ディレクトリ)も含めて探索してくれています。
特定拡張子のファイルのみ欲しい時は、 pathname の記述で指定しましょう。
ディレクトリだけ指定したい時は / で終えれば可能です。
また、 glob.glob の代わりに、 glob.iglob を使うと、結果をリストではなくイテレーターで返してくれます。
for f in glob.iglob("./**/*.txt", recursive=True):
print(f)
"""
./001.txt
./folder01/002.txt
./folder01/subfolder011/004.txt
"""
for f in glob.iglob("./**/", recursive=True):
print(f)
"""
./
./folder01/
./folder01/subfolder012/
./folder01/subfolder011/
./folder02/
./folder02/subfolder021/
"""
望む結果が得られました。