Python 

Pythonでフォルダ構造を可視化しよう!
第2回:globモジュール

2024/02/03

前回 は、osモジュールを使って再帰的にフォルダを検索する方法を解説しましたが、自前で関数を作らない方法もあります。

今回はglobモジュールを使った方法を解説していきます。

globの使い方

glob.glob() は「パターン」を使ったファイルの検索ができます。

パターンとは

パターンとは、パス文字列に*, ?, [] を挿入することで、特定のルールにマッチするパスを検索することができる特殊な文字のことです。

例えば、以下のパターンは「Blender 3.6」ディレクトリ直下の全てのフォルダ、ファイルにマッチします。

“C:\Program Files\Blender Foundation\Blender 3.6\*”

特定のファイルだけにマッチしたい場合は、パターンの後に拡張子を付けます。

“C:\Program Files\Blender Foundation\Blender 3.6\*.exe”

直下のディレクトリだけでなく、全てのサブディレクトリにマッチしたい場合は ** パターンを使います。

“C:\Program Files\Blender Foundation\Blender 3.6\**”

glob.glob() の使い方

glob.glob()* パターンで表現したパスを渡すことで、ディレクトリ直下の全てのフォルダ、ファイルのパスがリストとして返ってきます。

import glob

root_path = r"C:\Program Files\Blender Foundation\Blender 3.6\*"

items = glob.glob(root_path)

print("\n".join(items))
# >> C:\Program Files\Blender Foundation\Blender 3.6\3.6
# >> C:\Program Files\Blender Foundation\Blender 3.6\blender-launcher.exe
# >> C:\Program Files\Blender Foundation\Blender 3.6\blender.crt
# ...

print(type(items))
# >> <class 'list'>

全てのサブフォルダまで検索するには、** パターンを使い、引数を recursive=True にします。

root_path = r"C:\Program Files\Blender Foundation\Blender 3.6\*"
print(len(glob.glob(root_path)))
# >> 20

root_path = r"C:\Program Files\Blender Foundation\Blender 3.6\**"
print(len(glob.glob(root_path, recursive=True)))
# >> 6321

これだけで再帰的にディレクトリを検索できるのは便利ですね!

glob.glob()の引数

Pythonの公式ドキュメント (執筆時点はv3.12.1) から、glob.glob() の引数を解説します。

glob.glob() の引数は以下の通りです。

glob.glob(pathname, *, root_dir=None, dir_fd=None, recursive=False, include_hidden=False)

root_dir

バージョン3.5で追加された引数。デフォルト値はNone
公式ドキュメントには、以下のような解説があります。

root_dirが None でない場合、その値は検索のルートディレクトリを指定する path-like オブジェクトでなければなりません。
これは glob() を呼び出す前にカレントディレクトリを変更したのと同じ効果を持ちます。
pathname が相対パスの場合、戻り値のリストは root_dir からの相対パスを含むことになります。

正直分かりづらいですが、要するに root_dir に指定したパスがカレントディレクトリになるということです。

glob.glob(r"C:\Program Files\Blender Foundation\Blender 3.6\*")

# 以下と同義
glob.glob("*", root_dir=r"C:\Program Files\Blender Foundation\Blender 3.6")

dir_fd

こちらも、バージョン3.5で追加された引数。デフォルト値はNone
公式ドキュメントの解説は、以下の通り。

ディレクトリ記述子からの相対パス: dir_fd が None でない場合、その値はディレクトリを参照するファイル記述子である必要があり、また操作対象のファイルパスは相対パスである必要があります。
このときパスはファイル記述子が指すディレクトリからの相対パスと解釈されます。 パスが絶対パスの場合、 dir_fd は無視されます。

インテリマウントをとられている気分です。
筆者もこの記事を書くために調べるまでは、この引数の存在すら知りませんでした。

調べたところ、ファイル記述子 (ファイルディスクリプタ) とは、osがディレクトリを識別するために付けられる整数のようです。
osによってはdir_fdをサポートしていないようで、公式ドキュメントによると、dir_fdはUnixでのみ動作するとのことです。

使用しているプラットフォームでdir_fdをサポートしているかを調べるには、os.supports_dir_fd オブジェクトに関数が含まれているかどうかで調べられるようです。

glob.glob in os.supports_dir_fd
# >> False (windowsの場合)

recursive

デフォルト値はFalse
True にすることで、** パターンがすべてのサブディレクトリにマッチするようになります。

include_hidden

バージョン3.11で追加された引数。デフォルト値はFalse
True にすることで、隠しディレクトリも検索に含めることができます。

まとめ

今回は、globモジュールを使ってディレクトリを再帰的に解析する方法を解説しました。
使い方を知っておくだけでパッとディレクトリの構造を調べられるのは、非常に便利です。

次回は、os.walk() を使った方法を解説したいと思います。