本記事では、Pythonの標準ライブラリであるosモジュールのos.walkについて解説します。ディレクトリの中身を再帰的にたどりながら、ファイルやサブディレクトリの一覧を取得したい場合に非常に便利な関数です。
os.walkとは
os.walkは、指定されたディレクトリ内にあるすべてのファイルとサブディレクトリを再帰的に走査し、次の3つの要素を含むタプルを順番に返します。
- root: 現在処理しているディレクトリのパス(絶対パスまたは相対パス)
- dirs: 現在のディレクトリ内に含まれるサブディレクトリの名前のリスト
- files: 現在のディレクトリ内に含まれるファイルの名前のリスト
この関数は、指定したディレクトリ以下のすべてのディレクトリとファイルを自動的にたどり、各階層ごとにroot, dirs, filesを返します。
os.walkの使い方
基本的な使い方は非常にシンプルです。以下のコードは、カレントディレクトリ(から始めて、ディレクトリとその内容(ファイル・サブディレクトリ)を再帰的に取得します。
import os
# カレントディレクトリを再帰的に走査
for root, dirs, files in os.walk("."):
print("現在のディレクトリ:", root)
print("サブディレクトリ一覧:", dirs)
print("ファイル一覧:", files)
print("-----")
このコードを実行すると、指定したディレクトリ(この場合はカレントディレクトリ)内のファイルやサブディレクトリが階層ごとに表示されます。
例えば、以下のようなディレクトリ構造があるとします:
.
├── dir1
│ ├── file1.txt
│ └── file2.txt
├── dir2
│ └── file3.txt
└── file4.txt
実行結果は次のようになります:
現在のディレクトリ: .
サブディレクトリ一覧: ['dir1', 'dir2']
ファイル一覧: ['file4.txt']
-----
現在のディレクトリ: ./dir1
サブディレクトリ一覧: []
ファイル一覧: ['file1.txt', 'file2.txt']
-----
現在のディレクトリ: ./dir2
サブディレクトリ一覧: []
ファイル一覧: ['file3.txt']
os.walkが返す値
os.walkが返すタプルの構成要素について、もう少し詳しく説明します。
- root: 現在のディレクトリのパスです。例えば、最初に実行するカレントディレクトリは「.」となり、サブディレクトリに入るとそのサブディレクトリのパスが返されます。
- dirs: root内に存在するサブディレクトリの名前がリスト形式で返されます。もしサブディレクトリがなければ空のリスト([])が返されます。
- files: root内に存在するファイルの名前がリスト形式で返されます。ファイルがなければ空のリスト([])が返されます。
これにより、ディレクトリ内の構造を柔軟に処理できます。
フィルタリングを使う
os.walkでは、返されたリストから特定のファイルやディレクトリをフィルタリングすることができます。例えば、特定の拡張子のファイルだけを表示したい場合、以下のように書くことができます。
import os
for root, dirs, files in os.walk("."):
for file in files:
if file.endswith(".txt"):
print("テキストファイル:", os.path.join(root, file))
このコードでは、すべての.txtファイルだけを表示しています。ファイルの拡張子を条件にして検索する場合に便利です。
探索を制御する
dirsリストを操作することで、再帰的な探索の挙動を制御することができます。例えば、特定のディレクトリをスキップしたい場合、dirsリストからそのディレクトリを削除することができます。
import os
for root, dirs, files in os.walk("."):
if "skip_this_dir" in dirs:
dirs.remove("skip_this_dir") # このディレクトリは探索しない
print("現在のディレクトリ:", root)
print("サブディレクトリ一覧:", dirs)
print("ファイル一覧:", files)
print("-----")
このようにすると、skip_this_dirというディレクトリが見つかった場合、そのディレクトリ以下は探索しなくなります。再帰的な探索を制御したい場合に非常に便利です。
os.walkを使った実用的な例
例えば、ディレクトリ内に含まれるすべてのファイルを一括で処理したり、バックアップを取ったり、ディスクの使用量を集計するなどの用途でos.walkを活用できます。
ディレクトリ内のすべてのファイルをバックアップフォルダにコピーするコードは以下のようになります:
import os
import shutil
# バックアップ先ディレクトリ
backup_dir = "./backup"
# バックアップディレクトリがなければ作成
if not os.path.exists(backup_dir):
os.makedirs(backup_dir)
# ディレクトリ内のファイルを再帰的にコピー
for root, dirs, files in os.walk("."):
for file in files:
# コピー先のパス
src_file = os.path.join(root, file)
dest_file = os.path.join(backup_dir, file)
shutil.copy(src_file, dest_file)
ディレクトリの階層構造の把握
ディレクトリ全体に含まれるファイルやフォルダの構造を把握する場合、os.walkを使う手段が最も基本的です。一方で、もし単に特定のパターン(例:拡張子が.pyのファイル)のみを取得したい場合は、標準ライブラリのglobモジュールを使う方がシンプルで楽な場合があります。
import glob
# カレントディレクトリ以下にあるすべての.pyファイルを再帰的に取得
python_files = glob.glob("**/*.py", recursive=True)
for file in python_files:
print(file)
上記の例では、globモジュールのglob関数を用いて、.pyという拡張子を持つファイルを再帰的(ディレクトリを下りながら)に検索しています。大量のファイルの中から、条件に合ったものだけを簡単に集めたい場合は、このようにglobを使う方がコードがシンプルになることが多いです。逆に、すべてのディレクトリやファイルを詳細に制御しながら走査したい場合は、os.walkの方が柔軟です。
まとめ
- os.walkは、指定したディレクトリ内のファイルとサブディレクトリを再帰的に走査するための関数です。
- root, dirs, filesを返し、ディレクトリのパス、サブディレクトリ、ファイルのリストを取得できます。
- フィルタリングや探索の制御を行うことで、さまざまな用途に対応できます。
- 実際のファイル操作やバックアップ処理などで非常に便利に使えます。
- 特定のパターン(拡張子など)でファイルを検索したい場合は、globモジュールを使う方がシンプルな場合もあります。
os.walkを使うことで、ディレクトリ構造を簡単にたどりながら、ファイルを効率的に処理できます。まずはサンプルコードを実行し、ディレクトリを順にたどる感覚を掴んでみてください。