Python でディレクトリ内のファイルを列挙する (os.listdir, os.walk, glob)

ファイルを列挙する(再帰なし)

Python の os.listdir 関数を使うと、指定したディレクトリ内のファイルやディレクトリのパスをリストで取得できます。 カレントディレクトリや親ディレクトリを表す ... は、列挙の対象に含まれません。 列挙されたパスが、ディレクトリかどうかを調べたいときは os.path.isdir(path)、ファイルかどうかを調べたいときは os.path.isfile(path) で確認できます。

カレントディレクトリ内のディレクトリとファイルを列挙(1 階層のみ)
import os

for x in os.listdir('.'):
    if os.path.isdir(x):
        print('DIR:', x)
    else:
        print('FILE:', x)

ファイルを列挙する(再帰あり)

os.listdir で列挙する方法

os.listdir 関数で列挙した要素がディレクトリだった場合に、そのディレクトリに対しても os.listdir 関数を呼び出すようにすれば、ディレクトリ内のすべてのファイルを再帰的に列挙することができます。

import os

def enum_files(dir):
    entries = os.listdir(dir)
    for x in entries:
        path = os.path.join(dir, x)
        if os.path.isdir(path):
            for _ in enum_files(path): yield _
        else:
            yield path

if __name__ == '__main__':
    for path in enum_files('.'):
        print(path)
        # print(os.path.abspath(path))  # 絶対パスで出力する場合

os.walk で列挙する方法

os.walk 関数 を使用すると、再帰的なファイル列挙をさらに簡単に記述できます。 下記は 1 つのループ処理で記述していますが、下位のディレクトリにあるファイルまですべて列挙してくれます。 os.walk はデフォルトで再帰的にディレクトリを辿ってくれる ということです。

カレントディレクトリ以下、全ディレクトリの内容を表示
import os

for dirpath, dirs, files in os.walk("."):
    print("-" * 60)
    print(f"{dirpath} ディレクトリの情報:")
    print(f"dirs = {dirs}")
    print(f"files = {files}")

os.walk によって取得されるタプル要素には、それぞれ以下のような情報が格納されています。

  • dirpath … 現在検索中のディレクトリパス
  • dirsdirpath のディレクトリに含まれているディレクトリのリスト
  • filesdirpath のディレクトリに含まれているファイルのリスト

つまり、ディレクトリごとに上記のタプルが返されながらループが進んでいきます。 カレントディレクトリ以下のすべてのファイルのパスだけを列挙するには次のように files(タプルの 3 番目の要素)の内容だけ出力すれば OK です。 起点となるディレクトリのパス (dirpath) と join してやれば、そこからの相対パスを構築できます。

カレントディレクトリ以下のすべてのファイルの相対パスを表示
import os

for dirpath, dirs, files in os.walk('.'):
    for f in files:
        print(os.path.join(dirpath, f))
出力例
./a.txt
./b.txt
./foo/c.txt
./foo/d.txt
./foo/bar/e.txt
./foo/bar/f.txt
./hoge/g.txt

特定の拡張子のファイルだけ列挙したい場合 は、ファイル名の末尾を str.endswith メソッドでチェックすればよいでしょう。

.png ファイルのみを列挙
for f in files:
    if f.lower().endswith('.png'):
        print(os.path.join(dirpath, f))

endswith() にはタプルを渡せるので、複数の拡張子を OR 条件で列挙することもできます。

.png、.jpg、.svg ファイルを列挙
for f in files:
    if f.lower().endswith(('.png', '.jpg', '.svg')):
        print(os.path.join(dirpath, f))

os.path.splitext() を使用すれば、ファイル名をベースネームと拡張子に分離することができますが、拡張子のチェックだけであれば、endswith() を使った方がシンプルです。

glob で列挙する方法

ディレクトリ内の、特定の拡張子を持つファイルをすべて列挙したいときは、glob モジュールglob.glob 関数を使うのが一番簡単です。 次のようにすると、カレントディレクト以下の .png ファイルをすべて列挙できます。

.png 拡張子を持つファイルを列挙
import os
import glob

for x in glob.glob('**/*.png', recursive=True):
    print(x)

ただし、グロブでは複数の拡張子をまとめて処理できない ので、複数の拡張子のファイルを列挙したい場合は、その数だけ glob.glob() を呼び出さなければいけません。

.png あるいは .jpg 拡張子を持つファイルを列挙
import os
import glob

PATTERNS = ('**/*.png', '**/*.jpg')

def multi_glob(patterns):
    files = []
    for p in PATTERNS:
        files.extend(glob.glob(p, recursive=True))
    return files

for f in multi_glob(PATTERNS):
    print(f)

このような実装をするのであれば、os.walk を使って列挙した方が早いかもしれません。