YutaKaのPython教室

Python の文法やライブラリ、API、環境構築について画像・動画・ソースコード付きで徹底解説!

Python フォルダ内ファイル検索方法まとめ|pathlib.glob

Pythonのファイル操作用のモジュールpathlibというものがあります。

pathlibは、一連のファイル操作を一つのモジュールでこなせる非常に強力なモジュールです。

.glob()メソッドを使用すれば、様々な条件でのファイル・フォルダの検索を行うことが可能です。

しかし、実際にファイル検索する際には、次のような問題に直面することも:

  • pathlibを使って、ファイル検索するには具体的にどうすればいいの?
  • 特定の条件に合ったファイルを検索する方法は?
  • サブフォルダも含めて、全ファイル検索するにはどうするの?

こういった疑問を解決するために、この記事ではpathlib.glob()メソッドを使用したファイル検索方法について、図解付きで解説していきます。

フォルダ内ファイル検索の基本手順

この記事では、pathlibモジュールのPathを使用したファイル内検索方法について紹介します。

ファイル検索の基本手順は次の通りです。

手順 スクリプトの例
1. pathlibからPathクラスをインポート from pathlib import Path
2. 検索対象フォルダのPathオブジェクト作成 Path("検索フォルダ")
3. 条件に合ったファイル・フォルダを検索 Path.glob("検索条件")

Path.glob("検索条件")は、検索結果のジェネレータを返すので必要に応じて[リスト化]したり、for文を回したりします。

まずは実行例を紹介して、ファイル検索が想像以上に簡単だということをお伝えしたいと思います。

フォルダ内ファイル検索の実行例

例として、次のようなファイル構造を考えてみます。

Path.glob("検索条件")で、base_folder内の全てのファイル、フォルダを表示させてみましょう。

# pathlibからPathクラスをインポート
from pathlib2 import Path

# 検索対象フォルダのPathオブジェクト作成
BASE_FOLDER = Path("base_folder")

# 結果をfor文でprint表示するパターン
for p in BASE_FOLDER.glob("*"):
    print(p)
    
# base_folder\sample1.txt
# base_folder\sample2.txt
# base_folder\sub_folder1

# 結果をListにまとめるパターン
list(BASE_FOLDER.glob("*"))
# [WindowsPath('base_folder/sample1.txt'),
#  WindowsPath('base_folder/sample2.txt'),
#  WindowsPath('base_folder/sub_folder1')]

検索結果は、実行環境に応じたPathクラスとして返されます。

上記の例では、「任意のファイル・フォルダ」という検索条件を"*"という特殊文字で表現しています。

.glob()メソッドでは、特殊文字を上手に利用して検索条件を設定することがポイントです。

次に、どのような特殊文字が使用できるのか詳しく見ていきたいと思います。

検索で使用できる特殊文字

検索で使用できる特殊文字は、次の通りです。

特殊文字 意味 適用
* 0文字以上の任意の文字列 あらゆる文字(ワイルドカード)
? 1文字以上の任意の文字列  
[文字] [文字]内の文字 例)[ab]:a or b
[a-z]:a, b, c,…, z
[0-9]: 0, 1, 2,…, 9
[!文字] [!文字]内の文字以外 例)[!ab]:a or b以外
[!a-z]:a, b, c,…, z以外
[!0-9]: 0, 1, 2,…, 9以外
** Pathのフォルダとサブフォルダ **は、他の特殊文字と意味合いが異なる
検索範囲をPathフォルダと、そのサブフォルダにする

さらに追加で覚えておきたいポイントは、次の通りです。

ポイント 適用
特殊文字は、普通の文字と組合せ可 Ex) "012_*.txt"
  -> 「012_file_name.txt」や「012_ファイル.txt」にマッチ
正規表現のような
繰り返しを表す特殊文字はない
Ex) 「01.txt」, 「12.txt」の両方にマッチするには、
  ->"[0-9][0-9].txt"とする
サブフォルダはフォルダ名/で指定 Ex) sub_folder/*.txt
  ->「sub_folder内のtxtファイル」にのみマッチ

特殊文字は、正規表現と類似していますが、正規表現の全ての特殊文字を使えるわけではない点に注意ですね。

検索パターンテンプレ紹介

これらのポイントを踏まえたうえで、使用頻度が高そうな検索パターンを個別に紹介していきます。

検索内容 パターンテンプレ
フォルダ内の全ファイル・フォルダ Path.glob("*")
サブフォルダ内の全ファイル・フォルダ Path.glob("*/*")
サブフォルダも含めた全ファイル・フォルダ Path.glob("**")
特定の拡張子 Path.glob("*.拡張子")
Ex) ・Path.glob("*.txt")
      ・Path.glob("*.csv")
特定の文字で始まる Path.glob("特定の文字*")
Ex) ・Path.glob("2020*")
      ・Path.glob("sample*")
フォルダのみ抽出 Path.glob("検索条件")
+ Path.is_dir()組み合わせ
ファイルのみ抽出 Path.glob("検索条件")
+ Path.is_file()組み合わせ

これらのパターンについて、サンプルコードを紹介します。

ここでも次のようなファイル構造を想定してみます。

フォルダ内の全ファイル・フォルダ抽出

全ファイル、フォルダを抽出する場合は、検索条件に任意の文字列を意味する特殊文字"*"を指定します。

  • Path.glob("*")

これは、記事冒頭で紹介したサンプルと同じですね。

特殊文字*の検索範囲の意味をサンプルデータの例と一緒に図にしてみましょう。

サンプルデータで挙動を再確認してみましょう。

# 結果をfor文でprint表示するパターン
for p in BASE_FOLDER.glob("*"):
    print(p)
# base_folder\sample1.txt
# base_folder\sample2.txt
# base_folder\sub_folder1

# 結果をListにまとめるパターン
list(BASE_FOLDER.glob("*"))
# [WindowsPath('base_folder/sample1.txt'),
#  WindowsPath('base_folder/sample2.txt'),
#  WindowsPath('base_folder/sub_folder1')]

検索条件の意味がわかってくると、ファイル・フォルダの検索がとても簡単なことに気づきますね。

サブフォルダ内の全ファイル・フォルダ抽出

サブフォルダ内のファイル・フォルダを抽出する方法を紹介します。

この場合は、検索条件の始めにサブフォルダを意味する*/を追加します。

  • Path.glob("*/*")

検索条件*/*の意味を、サンプルデータの例と一緒に図にまとめてみます。

サンプルデータで挙動を再確認してみましょう。

# 結果をfor文でprint表示するパターン
for p in BASE_FOLDER.glob("*/*"):
    print(p)
# base_folder\sub_folder1\sample1_1.txt

# 結果をListにまとめるパターン
list(BASE_FOLDER.glob("*/*"))
# [WindowsPath('base_folder/sub_folder1/sample1_1.txt')]

"~/"を「~の中の」と解釈すると、検索条件の意味がよくわかってきますね。

特定のフォルダを指定したい場合は、次のように使うこともできます。

  • "特定のフォルダ名/検索条件"

Pathフォルダ+サブフォルダで全抽出

サブフォルダも含めて、全ファイル・フォルダを検索する場合を紹介します。

この場合は、検索条件の始めに「Pathフォルダとサブフォルダ」を意味する特殊文字**を追加します。

  • Path.glob("**/*")

ここで、**/*は、次のような意味になっています。サンプルデータの例とともに図示してみます。

サンプルデータで挙動を再確認してみましょう。

# 結果をfor文でprint表示するパターン
for p in BASE_FOLDER.glob("**/*"):
    print(p)
# base_folder\sample1.txt
# base_folder\sample2.txt
# base_folder\sub_folder1
# base_folder\sub_folder1\sample1_1.txt

# 結果をListにまとめるパターン
list(BASE_FOLDER.glob("**/*"))
# [WindowsPath('base_folder/sample1.txt'),
#  WindowsPath('base_folder/sample2.txt'),
#  WindowsPath('base_folder/sub_folder1'),
#  WindowsPath('base_folder/sub_folder1/sample1_1.txt')]

**は、正規表現にもなく、ファイル検索専用の特殊文字で、初めはとっつきにくい部分がありますが…。

Pathフォルダとサブフォルダ」という意味だと理解すれば、使い勝手のいい強力な特殊文字ですね。

特定の拡張子で抽出

特定の拡張子のファイルを抽出する場合は、特殊文字"*"と拡張子を組み合わせます。

  • Path.glob("*.拡張子")
    • Ex1) txtファイルの場合 -> Path.glob("*.txt")
    • Ex2) csvファイルの場合 -> Path.glob("*.csv")

ここで、"*.拡張子"は次のような意味です。.txtの例と一緒に確認してみましょう。

これは使用頻度が高いので、サブファルダ内、Pathフォルダおよびサブフォルダ内全てを検索する場合も含めて表に整理してみます。

検索先 パターンテンプレ
Pathフォルダ内 Path.glob("*.拡張子")
サブフォルダ内 Path.glob("*/*.拡張子")
Pathフォルダ+サブフォルダ内 Path.glob("**/*.拡張子")

サンプルデータで挙動を再確認してみましょう。

# Pathフォルダ内を検索
list(BASE_FOLDER.glob("*.txt"))
# [WindowsPath('base_folder/sample1.txt'),
#  WindowsPath('base_folder/sample2.txt')]

# Pathフォルダ+サブフォルダ内を検索
list(BASE_FOLDER.glob("**/*.txt"))
# [WindowsPath('base_folder/sample1.txt'),
#  WindowsPath('base_folder/sample2.txt'),
#  WindowsPath('base_folder/sub_folder1/sample1_1.txt')]

特定の文字列で始まる

特定の文字列で始まるファイル・フォルダを抽出する場合は、検索対象の文字列と特殊文字"*"を組み合わせます。

  • Path.glob("特定の文字*")
    • Ex1) "2020"から始まる場合 -> Path.glob("2020*")
    • Ex2) "sampleから始まる場合 -> Path.glob("sample*")

サブファルダ内、Pathフォルダおよびサブフォルダ内全てを検索する場合も含めて表に整理してみます。

検索先 パターンテンプレ
Pathフォルダ内 Path.glob("特定の文字*")
サブフォルダ内 Path.glob("*/特定の文字*")
Pathフォルダ+サブフォルダ内 Path.glob("**/特定の文字*")

サンプルデータで挙動を再確認してみましょう。

# Pathフォルダ内を検索
list(BASE_FOLDER.glob("sample1*"))
# [WindowsPath('base_folder/sample1.txt')]

# Pathフォルダ+サブフォルダ内を検索
list(BASE_FOLDER.glob("**/sample1*"))
# [WindowsPath('base_folder/sample1.txt'),
#  WindowsPath('base_folder/sub_folder1/sample1_1.txt')]

フォルダのみ・ファイルのみを抽出

フォルダのみ、ファイルのみを抽出する方法を紹介します。

Pathオブジェクトには、Pathがフォルダなのか、ファイルなのか判定するメソッドがあります。

判定内容 メソッド名 結果
フォルダかどうか .is_dir() True or False
ファイルかどうか .is_file() True or False

Path.glob()の結果もPathオブジェクトなので、if文と組み合わせてフォルダ・ファイルの判定が可能です。

まずはフォルダのみを抽出する例を見てみましょう。

# 結果をfor文でprint表示するパターン
for p in BASE_FOLDER.glob("*"):
    if p.is_dir():
        # 処理内容
        print(p)
# 実行結果
# base_folder\sub_folder1

# 結果をListにまとめるパターン
[p for p in BASE_FOLDER.glob("*") if p.is_dir()]
# [WindowsPath('base_folder/sub_folder1')]

次にファイルのみを抽出する例を見てみましょう。

# 結果をfor文でprint表示するパターン
for p in BASE_FOLDER.glob("*"):
    if p.is_file():
        # 処理内容
        print(p)
# 実行結果
# base_folder\sample1.txt
# base_folder\sample2.txt

# 結果をListにまとめるパターン
[p for p in BASE_FOLDER.glob("*") if p.is_file()]
# [WindowsPath('base_folder/sample1.txt'),
#  WindowsPath('base_folder/sample2.txt')]

ここまで覚えると、ファイル検索がかなり自由にできるようになってくると思います。

様々な条件を組み合わせて自由にファイル検索を行いましょう。

より複雑なファイル検索をしたい場合は、次に紹介する正規表現との組み合わせも選択肢の一つです。

正規表現による検索条件設定

.glob()メソッドで使用できる特殊文字は、**, *, ?, [], [!]のみでした。

正規表現とは異なり、繰り返しを表現する特殊文字がないところが難点です。

繰り返しを含めたより複雑な条件で検索したい場合には、素直に正規表現と組み合わせると良いです。

例えば、次のようなフォルダを考えてみましょう。

この中から1995~2000のファイルを検索したい場合は、どうしたら良いでしょうか?

正規表現を使えば簡単ですね。

import re
BASE_FOLDER2 = Path("base_folder2")

data_1995_to_2000 = []
for p in BASE_FOLDER2.glob("*.csv"):
    # 正規表現でPathから数字4ケタ取得
    res = re.search("\d{4}", str(p))
    year = int(res.group())
    
    # 数字4ケタが条件を満たすか判定
    if 1995 <= year <=2000:
        data_1995_to_2000.append(p)
        
print(data_1995_to_2000)
# [WindowsPath('base_folder2/1995_Data.csv'),
#  WindowsPath('base_folder2/2000_Data.csv')]

この例では、ファイル数が少なかったですが、無数のファイルの中からデータ検索する場合を考えると正規表現の重要性がわかりますね。

  • 【参考】pythonの正規表現については、次の記事で詳しく解説しています。
≫Python正規表現パターンを図解&サンプルで本当にわかりやすく解説
Pythonのreモジュールで正規表現パターンを作成する際に重要な3つのポイントを解説します。①特定の文字の繰り返しを指定 ②数値や文字、空白など条件による文字条件の指定 ③グループ化によるパターン内の特定部分の抽出
www.yutaka-note.com/entry/regex_01
 
≫Python 正規表現の検索を本当にわかりやすく解説
Pythonで正規表現を使用して、パターン検索する方法をわかりやすく解説しています。① 検索メソッド(関数)の実行方法② 各メソッドの紹介(単独検索search()、全体検索findallなど)③ 検索結果の出力であるMatchオブジェクトの内容
www.yutaka-note.com/entry/regex_02
 

pathlibとpathlib2どっちを使う?

最後にpathlibモジュールについて、補足事項です。

pathlib関連のモジュールには、pathlibpathlib2の2種類があります。

pathlib2≫ドキュメントを参考に、2つの違いを簡単にまとめると次の通りです。

モジュール インストール要否 モジュールメンテナンス
pathlib Python標準モジュールなので不要 メンテナンスされていない
pathlib2 pipcondaでインストール必要 継続してメンテナンスされている

メンテナンスが継続されているという点から、私は基本的にpathlib2を使用しています。

(ちなみに、condaでいろいろモジュールをインストールしていると、いつの間にかpathlib2がインストールされていることも多いです。)

pipおよびcondapathlib2をインストール際のコマンドは次の通りです。

pip install pathlib2
conda install pathlib2

Pythonで作業を効率化する方法

今回はpathlib.glob()メソッドでファイル検索する方法を解説しました。

Pythonを使えば、簡単なスクリプトで作業を劇的に効率化することも可能です!

Pythonの効率化関係で言えば、次の記事で紹介しているような本が自動化の本がおススメです。

≫【レビュー】退屈なことはPythonにやらせよう | 単純作業は自動化
名著「退屈なことはPythonにやらせよう 」をレビュー!単純作業を自動化して、自分が本当にしたいことのために時間を確保していこう!所要時間やできるようになったことを紹介!この本を参考にして作成した、自作自動化スクリプトも紹介しています!
www.yutaka-note.com/entry/python_jido
 
≫独学でデータ分析を勉強するオススメ学習本
独学でのpythonデータ分析勉強に役立ったおススメ書籍を紹介していきます。業務でそれなりにデータ分析を行えるまで、いろいろな試行錯誤をしてきましたが、もし自分が今ゼロから勉強する立場ならどうするのがいいのか考えてみました。以下では、入門書、個別モジュール用、実践用の3つの視点でおススメ本を紹介していきます。
www.yutaka-note.com/entry/data_analysis