↓ メインコンテンツへスキップ
  1. 第05講 再帰関数(2/2; 探索)/

ディレクトリ構造の探索

ディレクトリ内の探索
#

指定されたディレクトリ内のファイル数、ディレクトリ数を数えるには、ディレクトリの一覧を取得し、その中でディレクトリ数、ファイル数を数える必要があります。 また、取得した一覧の中のディレクトリに対して、同様にディレクトリ内のファイル数、ディレクトリ数を数える必要があります。 このような処理は再帰呼び出しを用いて実装できます。

os.listdir
#

ディレクトリの一覧を取得するには、os.listdir 関数を用います。 取得したパスがディレクトリであるかを判定するには、os.path.isdir() 関数を用います。 同様に、ファイルであるかを判定するには、os.path.isfile() 関数を用います。 これらの関数を用いるには、os モジュールをインポートする必要があります。

なお、以下のプログラムの実行結果は、次の dirs.zip をダウンロード、展開してできたディレクトリ構造(root)を想定しています。 また、以下の実行例のリストの順序は必ずしもこの通りではありません。

📥 dirs.zipのダウンロード

>>> import os
>>> dirs = os.listdir('root')
>>> dirs
['dir2', 'dir5', 'dir4', 'dir3', 'dir1']
>>> >>> os.listdir("root" + dirs[0])     # listdir はパスを意識しているわけではない。
Traceback (most recent call last):       # 指定されて初めて、そのパスの存在確認を行う。
  File "<stdin>", line 1, in <module>    # そのため、/ のあるなしで挙動が変わる。
FileNotFoundError: [Errno 2] No such file or directory: 'rootdir2' # root/dir2 ではなく、rootdir2 であるため、エラーが発生する。
>>> os.listdir("root/" + dirs[0])        # しっかりと相対パスを指定すると、正しく動作する。
['file3', 'file2', 'file1']
>>> path = os.path.join("root", dirs[0]) # os.path.join を用いると、最後のスラッシュの有無を気にしなくて良い。
>>> path
root/dir2
>>> os.listdir(path)
['file3', 'file2', 'file1']

例題 指定されたディレクトリ以下のファイル数、ディレクトリ数
#

指定されたディレクトリ以下のファイル数、ディレクトリ数を数えるプログラム count_dirs.py を作成してください。 count_dirs という関数を用意し、与えられたパス内のファイル数、ディレクトリ数をタプルで返すようにしてください。 この関数で与えられたパスのファイル、ディレクトリ一覧を取得し、その一覧の中のディレクトリに対して、 再度 count_dirs を呼び出してください。 呼び出した結果として、得られるファイル数、ディレクトリ数を加算して返すことで、トータルのファイル数、ディレクトリ数を求められます。

import os
import sys

def count_dirs(path):
    files = 0
    if os.path.isdir(path): # pathがディレクトリの場合は、ディレクトリ数を1にする。
        dirs = 1
    else:                   # そうでない場合、ディレクトリ数の初期値は 0 にする。
        dirs = 0

    for item in os.listdir(path):
        if os.path.isdir(os.path.join(path, item)):     # ディレクトリの場合は
            f, d = count_dirs(os.path.join(path, item)) # path + item を起点に再度 count_dirs を呼び出す
            dirs = dirs + d                             # ディレクトリ数を加算する。
            files = files + f                           # ファイル数も加算する。
        elif os.path.isfile(os.path.join(path, item)):  # ファイルの場合は
            files += 1                                  # ファイル数をインクリメントする。
    return (files, dirs)                                # ファイル数、ディレクトリ数を返す

for i in sys.argv[1:]:
    f, d = count_dirs(i)
    print(f"{i}: {f} files, {d} directories")

このプログラを実行すると、指定されたディレクトリ以下のファイル数、ディレクトリ数が表示されます。

$ python count_dirs.py root
root: 27 files, 9 directories
$ find root -type f | wc -l # root 以下のファイル数を確認する。
27
$ find root -type d | wc -l # root 以下のディレクトリ数を確認する。
9