メインコンテンツへスキップ
  1. 第07講 再帰関数(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