プログラムで大量のファイルを処理したい時、ディレクトリ内のファイル一覧を正確かつ効率よく取得することが肝心です。Pythonなら標準モジュールを使って簡単に一覧取得できますが、選ぶメソッドや処理方法によって速度やメモリの使い勝手が大きく変わります。この記事では、「Python ディレクトリ ファイル 一覧 取得」のキーワードに即して、最新情報を交えた複数の方法、注意点、応用例を解説します。
ディレクトリ探査の基礎から大量データの一括処理まで、実践的なコードや比較表を通じてステップバイステップでマスターしましょう。
Python ディレクトリ ファイル 一覧 取得 の基本的な方法まとめ
まず「Python ディレクトリ ファイル 一覧 取得」を初心者にも分かりやすく実現する基本手法を整理します。どの方法がどのような場面で優れているか、標準モジュールやパターンマッチングを交えて理解しましょう。
複数のディレクトリ階層がある場合やフィルタリングが必要な場合にも対応できるよう、各手段の特徴と使いどころを押さえます。
os.listdir を使ってファイル一覧を取得する
最も基本的な方法が os モジュールの listdir 関数を使う方法です。指定したパスからすべてのファイルとサブディレクトリの名前を取得できます。ファイルかどうかを判定したり操作対象を限定したい場合は、os.path.isfile と組み合わせることで実用的になります。
ただ、サブディレクトリを含めて再帰的に取得する用途や、数万・数十万ファイルがあるディレクトリではリストの生成コストやメモリ使用量が問題になり得ます。
os.walk を使って再帰的に取得する
os.walk は指定したディレクトリ以下にあるすべてのサブディレクトリとファイルを巡回するジェネレータ的関数です。戻り値として (ディレクトリパス, サブディレクトリ名リスト, ファイル名リスト) のタプルを階層ごとに取得できます。
再帰処理を自前で書く手間を省け、階層構造のまま処理できるため、大量のデータを含むプロジェクトでよく使われます。
ただし、ディレクトリの数・深さ・ファイル数が非常に多い場合は実行時間やメモリ消費の最適化が必要です。
pathlib を使ったモダンな方法
pathlib モジュールはオブジェクト指向でパス操作ができるモジュールです。Path オブジェクトを使って iterdir や glob, rglob メソッドでファイル一覧を取得できます。
glob パターンを使って拡張子でのフィルタリングや、** を使った再帰探索が簡潔に書けます。
pathlib は可読性が高く、コード保守性に優れます。標準的なディレクトリ操作には十分な性能を持ち、最新の Python バージョンで推奨されるスタイルです。
大量のファイルを一括処理するための性能と効率
数万~数百万のファイルが存在するディレクトリでファイル一覧を取得する時、どの方法でも同じではありません。ここでは速度・メモリ使用量・スケーラビリティの観点から比較し、どちらを選ぶべきかを明確にします。
os.scandir が持つ効率性のメリット
os.scandir は DirEntry オブジェクトを返し、名前、パスやファイル属性の取得を遅延評価で行えるため、os.listdir よりも高速でメモリ使用が少ないです。特にファイルかディレクトリかを判別する場合に有利です。
大量ファイルのループ処理時、余分な文字列操作を減らせるため、パフォーマンスが向上します。
最新のバージョンでは scandir を内部で使う関数が多く、標準的に採用すべき選択肢となっています。
ジェネレータ/イテレータを使ってメモリを節約する
全ファイルを一度にリストとして取得するのではなく、yield を使ったジェネレータ関数や iterdir/os.walk のイテレータ形式を活用することで、メモリ使用量を抑えつつ逐次処理できます。
ファイルの内容を順次読み込んだり、ストリーミング処理を行うような場面ではこの方法が特に有効です。
また、処理中にエラーが発生しても部分的な結果を扱える設計にすると、安全性が高まります。
マルチプロセスや非同期処理の活用可能性
多数のファイルを処理する際、I/O 操作がネックになることがあります。ファイル一覧の取得自体は CPU より I/O に依存しますが、その後の処理(読み込みや解析)を並列化することで全体の処理時間を短縮できます。
マルチプロセス/マルチスレッド、および非同期フレームワークを活用することで、ディスクアクセスの待ち時間を隠蔽できます。
ただし、ディスクやファイルシステムの種類、ソフトウェアのロックなどに注意が必要です。
フィルタリングと条件付き取得の実践例
単にファイルを取得するだけでなく、特定の拡張子、サイズ、更新日時などの条件を付けて絞り込みたい場面があります。ここでは具体的なフィルタリング方法とその例を示します。
拡張子での絞り込み
glob や pathlib.glob/rglob を使うと、*.txt や *.csv といったパターンでフィルタできます。glob はワイルドカードや ** を指定することでサブディレクトリも含められます。
また、os.walk で取得したファイル名に対して endswith メソッドを使う方法も一般的です。複数拡張子を条件とする場合はタプルで指定できます。
大文字小文字を区別するファイルシステムかどうかを考慮して処理を行うとトラブルが少なくなります。
ファイルのサイズ/更新日時でフィルタする
ファイルのメタデータ(stat情報)を取得して、サイズ以上/以下、更新日時がいつ以前/以降かなどで条件を付けられます。
pathlib.Path.stat や os.stat を使ってファイル情報を取得できます。
ファイルシステムや OS によってタイムスタンプの精度が異なるので、必要なら丸め処理やタイムゾーンの管理をすることも大切です。
除外ディレクトリや隠しファイルの扱い
サブディレクトリを探索する際に特定のディレクトリを除外したいことがあります。os.walk や pathlib.rglob を使うとき、除外リストを設けて無視する実装が可能です。
隠しファイルやドットスタートのファイルも OS によって扱いが異なるので、 is_hidden か name.startswith(記号)を使う条件を付けて扱いを統一するとよいです。
これら条件付きフィルタリングを設計することで、目的以外のファイル検索を効率よく制御できます。
サンプルコード集:すぐに使える実践的スクリプト
実際にプロジェクトで使える具体的なサンプルコードを紹介します。ディレクトリを指定し、フィルタや出力形式を指定できるようなスクリプトを例示します。
シンプルにファイル名だけを取得するコード例
以下は指定したディレクトリ内のファイルのみを取得するシンプルな関数です。サブディレクトリは無視します。
この程度の処理でよいケースでは、余計な負荷をかけずに済みます。
import os
def list_files(dir_path):
try:
return [f for f in os.listdir(dir_path)
if os.path.isfile(os.path.join(dir_path, f))]
except Exception as e:
return []
再帰的にすべてのファイルパスを取得するコード例
サブディレクトリ以下も含めて全ファイルのパスを取得し、さらに拡張子で絞り込む例です。ジェネレータ形式なのでメモリ効率が良くなります。
import os
def gen_files(path, exts=None):
for root, dirs, files in os.walk(path):
for fname in files:
if exts is None or fname.endswith(exts):
yield os.path.join(root, fname)
Pathlib を使ってモダンに書く例
最新スタイルで書きたい方向けに pathlib を利用したコードです。パスの操作がオブジェクトを通じて行えるため可読性が高いです。
from pathlib import Path
def list_files_modern(path, exts=None, recursive=False):
p = Path(path)
if recursive:
iterator = p.rglob('*')
else:
iterator = p.iterdir()
for entry in iterator:
if entry.is_file():
if exts is None or entry.suffix in exts:
yield entry
トラブルシューティングとよくある疑問への対応
実際の現場では、ファイル数が多すぎたりパーミッションの問題があったり、文字コードや OS の互換性で躓くことがあります。ここではよくある問題とその解決策をまとめます。
ディレクトリが存在しない・アクセス権がない場合のエラー処理
指定したディレクトリが存在しないと FileNotFound エラー、読み込み権限がないと PermissionError が発生します。例外処理を入れてエラー理由を明確に出力することが重要です。
try except を使って対応し、ログ記録やデフォルト値の返却などを設計すると堅牢なスクリプトになります。
Unicode や文字エンコーディングの問題
ファイル名に非ASCII文字を含む場合、OS や環境によって扱いに差異があります。pathlib は文字列型の扱いが洗練されており、文字エンコーディングの自動的な処理が強化されているため有利なことがあります。
環境変数やファイルシステムの設定(UTF-8 かその他か)を確認し、可能なら正規化処理を行うと文字列比較やフィルタリングでの誤判定を防げます。
大量ファイルでの処理速度が遅いと感じたら
遅さを感じるときは以下を確認してください。
- 処理しているファイル数
- ディスクの種類(SSD/HDD/ネットワークドライブ)
- 処理内容(メタデータ取得、ファイル読み込みなど)
- 条件フィルタの順序(軽い条件を先に)
また os.scandir や pathlib.iterdir を使い、ジェネレータ形式で処理を流れるようにするとオーバーヘッドが減ります。並列処理を検討することも有効です。
標準モジュール同士の具体的な比較表
複数の方法を並べて、「速度」「メモリ使用」「可読性」「再帰の対応」などの軸で比較します。用途に合わせて最適な手法を選べるようになります。
| 手法 | 速度 | メモリ使用量 | 可読性・保守性 | 再帰対応 |
|---|---|---|---|---|
| os.listdir + os.path.isfile | 高速(小規模ディレクトリ) | 中程度(一覧全体をリストに保持) | コードが直感的 | 非対応(自前で処理) |
| os.walk | 遅くなることあり(深い階層で) | 高(リスト拡張や階層情報を保存) | 標準的で理解容易 | 標準でサポート |
| os.scandir | 高速(エントリ属性を遅延評価) | 低~中(エントリオブジェクトを迭代) | 少し複雑になる場合あり | 自前で再帰処理を追加可能 |
| pathlib (iterdir / rglob) | 十分高速、可読性高 | 中程度(オブジェクト生成のコストあり) | 非常に良い(スタイル統一しやすい) | 再帰対応あり(rglob など) |
応用シナリオ別の使い分けのベストプラクティス
ファイル一覧取得は目的次第で適した実装が変わります。ここではよくある応用例に応じて推奨方法を提示します。
バッチ処理やログ解析など大量一括処理で使うパターン
処理対象が膨大なファイル群である場合、ジェネレータ形式を使い逐次処理するスタイルがメモリ負荷を抑える鍵になります。os.scandir や pathlib.rglob を採用し、ファイル名ではなくパス情報+メタデータ取得を必要なものだけ行う設計が有効です。
またディスク I/O の待ち時間を減らすため、並列/非同期読み込みを併用することも検討しましょう。
ファイルの種類や拡張子が限定されている場合の処理
例えば画像ファイルだけ、テキストファイルだけを処理したい場合、glob や pathlib で拡張子フィルタをかけるのが簡潔で効率的です。endswith を使った絞り込みも標準的ですが、複雑なパターンなら fnmatch モジュールを使うと柔軟性が上がります。
GUI アプリケーションや Webアプリケーションでの利用
ユーザーがディレクトリを選ぶような GUI/Web の場面では、バックエンドで非同期処理を採用すると応答性が保たれます。一覧取得中の進捗バー表示やキャンセル機能を設けると UX が向上します。
またセキュリティ観点で不要なディレクトリへのアクセス制限やパス正規化を行うことも忘れてはいけません。
まとめ
「Python ディレクトリ ファイル 一覧 取得」は用途に応じて正しい手法を選ぶことが重要です。
基本手段としては os.listdir, os.walk, os.scandir, pathlib の各メソッドがあり、可読性・効率性・再帰対応の観点で異なる特性があります。
大量のデータを扱う際はジェネレータ形式を使うこと、I/O 操作やフィルタリングを適切に配分することが処理性能を大きく左右します。
ここで紹介したサンプルコードや比較表を参考に、ご自身の用途に最適な方法を選択して実装を進めてみてください。
コメント