Python globで特定の拡張子のファイルを抽出する方法:徹底解説
Pythonにおけるファイル操作は、プログラミングの基礎であり、データ分析、システム管理、自動化など、様々な分野で必要不可欠なスキルです。数あるファイル操作モジュールの中でも、globモジュールは、特定のパターンに一致するファイルパスを効率的に取得できるため、非常に重要な役割を果たします。この記事では、globモジュールの基本的な使い方から、応用的なテクニックまで、特定の拡張子を持つファイルを抽出する方法を中心に、詳細に解説します。
1. globモジュールとは?
globモジュールは、Unixシェルで使用されるファイル名パターン(globパターン)に基づいて、ファイルやディレクトリのパス名を検索するための機能を提供します。ワイルドカード文字(*、?、[])を使って柔軟なパターンマッチングを実現し、特定の条件に合致するファイルのリストを簡単に取得できます。
1.1. globモジュールのインポート
globモジュールを使用するには、まずPythonスクリプトにインポートする必要があります。
python
import glob
1.2. 基本的なglobパターンの構文
globモジュールで使用されるglobパターンは、以下のワイルドカード文字で構成されます。
*(アスタリスク): 0文字以上の任意の文字列にマッチします。?(クエスチョンマーク): 任意の1文字にマッチします。[](角括弧): 角括弧内の文字のいずれか1文字にマッチします。 範囲指定も可能です (例:[a-z]は a から z までの任意の小文字にマッチします)。[!...](否定の角括弧): 角括弧内の文字以外の任意の1文字にマッチします。
2. globモジュールの主要関数
globモジュールには、主に以下の2つの関数が用意されています。
glob.glob(pathname, *, recursive=False, include_hidden=False): 指定されたglobパターンに一致するすべてのパス名をリストとして返します。glob.iglob(pathname, *, recursive=False, include_hidden=False):glob.glob()と同様ですが、イテレータを返します。大規模なファイルシステムを扱う場合にメモリ効率が良いです。
2.1. glob.glob() の使い方
glob.glob() 関数は、最も基本的なglobパターン検索を行います。
“`python
import glob
現在のディレクトリにあるすべての.txtファイルを検索
txt_files = glob.glob(“*.txt”)
print(txt_files)
サブディレクトリにあるすべての.txtファイルを再帰的に検索
recursive=Trueを指定することで、サブディレクトリを探索します。
txt_files_recursive = glob.glob(“*/.txt”, recursive=True)
print(txt_files_recursive)
“`
この例では、*.txt というパターンを使って、現在のディレクトリにあるすべての.txtファイルを検索しています。* は任意の文字列にマッチするため、ファイル名が何であれ、拡張子が.txtであればリストに含まれます。 recursive=True パラメータを使用すると、指定されたディレクトリ以下のサブディレクトリを再帰的に検索できます。
2.2. glob.iglob() の使い方
glob.iglob() 関数は、イテレータを返すため、大規模なファイルシステムでメモリを効率的に使用できます。
“`python
import glob
現在のディレクトリにあるすべての.txtファイルを検索し、イテレータで処理
txt_files_iterator = glob.iglob(“*.txt”)
for file_path in txt_files_iterator:
print(file_path)
“`
この例では、glob.iglob() を使用して.txtファイルのイテレータを取得し、forループで各ファイルパスを処理しています。
3. 特定の拡張子を持つファイルを抽出する
globモジュールを使って特定の拡張子を持つファイルを抽出するには、globパターンを適切に指定する必要があります。
3.1. 単一の拡張子を指定する
最も単純なケースは、特定の1つの拡張子を持つファイルを抽出する場合です。
“`python
import glob
現在のディレクトリにあるすべての.jpgファイルを検索
jpg_files = glob.glob(“*.jpg”)
print(jpg_files)
“`
この例では、*.jpg というパターンを使って、現在のディレクトリにあるすべての.jpgファイルを検索しています。
3.2. 複数の拡張子を指定する
複数の拡張子を持つファイルを抽出するには、いくつかの方法があります。
方法1: 角括弧 [] を使用する
角括弧を使って、複数の拡張子をまとめて指定できます。
“`python
import glob
現在のディレクトリにあるすべての.jpg, .png, .gifファイルを検索
image_files = glob.glob(“*.[jpg|png|gif]”) # これは動作しません。
正しい方法は以下
image_files_jpg = glob.glob(“.jpg”)
image_files_png = glob.glob(“.png”)
image_files_gif = glob.glob(“*.gif”)
image_files = image_files_jpg + image_files_png + image_files_gif
print(image_files)
“`
注意: 角括弧 [] を使用する方法は、拡張子の組み合わせに完全には対応できません。上記の例では意図通りに動作しない可能性があります。より確実な方法は、それぞれの拡張子で検索した結果を結合することです。
方法2: os.path.splitext() を使用する
os.path.splitext() 関数を使って、ファイル名と拡張子を分離し、拡張子を比較する方法です。
“`python
import glob
import os
現在のディレクトリにあるすべての.jpg, .png, .gifファイルを検索
image_files = []
all_files = glob.glob(“.“) # すべてのファイルを検索
for file_path in all_files:
root, ext = os.path.splitext(file_path)
if ext.lower() in [“.jpg”, “.png”, “.gif”]:
image_files.append(file_path)
print(image_files)
“`
この例では、まず glob.glob("*.*") で現在のディレクトリにあるすべてのファイルを検索し、os.path.splitext() で各ファイルの拡張子を取得しています。 そして、取得した拡張子が .jpg, .png, .gif のいずれかに一致する場合、image_files リストに追加しています。.lower() メソッドを使用して、大文字小文字の違いを無視するようにしています。
方法3: リスト内包表記を使用する
リスト内包表記を使うと、コードをより簡潔に記述できます。
“`python
import glob
import os
現在のディレクトリにあるすべての.jpg, .png, .gifファイルを検索
image_files = [
file_path
for file_path in glob.glob(“.“)
if os.path.splitext(file_path)[1].lower() in [“.jpg”, “.png”, “.gif”]
]
print(image_files)
“`
この例では、リスト内包表記を使って、上記のコードを1行で記述しています。
4. サブディレクトリを再帰的に検索する
glob.glob() 関数に recursive=True パラメータを指定することで、サブディレクトリを再帰的に検索できます。
“`python
import glob
すべてのサブディレクトリにあるすべての.txtファイルを再帰的に検索
txt_files = glob.glob(“*/.txt”, recursive=True)
print(txt_files)
“`
この例では、**/*.txt というパターンを使って、すべてのサブディレクトリにあるすべての.txtファイルを検索しています。** は、0個以上のディレクトリを意味します。
5. 大文字・小文字を区別しない検索
globモジュールは、デフォルトでは大文字・小文字を区別して検索を行います。大文字・小文字を区別しない検索を行うには、os.path.normcase() 関数を使用するか、reモジュールを使用します。
5.1. os.path.normcase() を使用する
os.path.normcase() 関数は、ファイル名を小文字に変換します(Windowsの場合)。
“`python
import glob
import os
現在のディレクトリにあるすべての.TXTファイルを検索 (大文字・小文字を区別しない)
txt_files = [
file_path
for file_path in glob.glob(“*.TXT”)
if os.path.normcase(file_path).endswith(“.txt”)
]
print(txt_files)
“`
この例では、まず glob.glob("*.TXT") で大文字の拡張子を持つファイルを検索し、os.path.normcase() でファイル名を小文字に変換し、.endswith(".txt") で拡張子を確認しています。
5.2. re モジュールを使用する
reモジュールを使うと、より複雑な正規表現によるパターンマッチングが可能です。大文字・小文字を区別しない検索を行うには、re.IGNORECASE フラグを指定します。
“`python
import glob
import re
現在のディレクトリにあるすべての.txtファイルを検索 (大文字・小文字を区別しない)
txt_files = [
file_path
for file_path in glob.glob(“.“)
if re.search(r”.txt$”, file_path, re.IGNORECASE)
]
print(txt_files)
“`
この例では、re.search(r"\.txt$", file_path, re.IGNORECASE) で、ファイル名が.txtで終わるかどうかを、大文字・小文字を区別せずに確認しています。 r"\.txt$" は正規表現で、. はエスケープする必要があり、$ は文字列の末尾を意味します。 re.IGNORECASE フラグを指定することで、大文字・小文字を区別しない検索を行います。
6. Pathlib モジュールとの連携
Python 3.4以降では、pathlibモジュールを使って、よりオブジェクト指向的な方法でファイルパスを操作できます。globモジュールとpathlibモジュールを組み合わせることで、より柔軟なファイル操作を実現できます。
“`python
import glob
from pathlib import Path
現在のディレクトリをPathオブジェクトとして取得
current_dir = Path(“.”)
現在のディレクトリにあるすべての.txtファイルを検索
txt_files = list(current_dir.glob(“*.txt”))
print(txt_files)
サブディレクトリにあるすべての.txtファイルを再帰的に検索
txt_files_recursive = list(current_dir.rglob(“*.txt”))
print(txt_files_recursive)
“`
この例では、Path(".") で現在のディレクトリを Path オブジェクトとして取得し、glob("*.txt") で現在のディレクトリにあるすべての.txtファイルを検索しています。 rglob("*.txt") は、recursive=True を指定した場合と同じように、サブディレクトリを再帰的に検索します。 list() 関数でイテレータをリストに変換しています。
7. エラーハンドリング
globモジュールを使用する際には、ファイルが見つからない場合や権限がない場合など、様々なエラーが発生する可能性があります。try-except ブロックを使って、これらのエラーを適切に処理することが重要です。
“`python
import glob
try:
# ファイルを検索
txt_files = glob.glob(“*.txt”)
print(txt_files)
except OSError as e:
# エラーが発生した場合の処理
print(f”エラーが発生しました: {e}”)
“`
この例では、try ブロック内で glob.glob("*.txt") を実行し、OSError が発生した場合に except ブロックでエラーメッセージを表示しています。
8. 実践的な例
例1: 特定のディレクトリにある画像ファイルを別のディレクトリにコピーする
“`python
import glob
import shutil
import os
ソースディレクトリとデスティネーションディレクトリを指定
source_dir = “images”
destination_dir = “processed_images”
デスティネーションディレクトリが存在しない場合は作成
if not os.path.exists(destination_dir):
os.makedirs(destination_dir)
ソースディレクトリにあるすべての.jpg, .png, .gifファイルを検索
image_files = []
for ext in [“.jpg”, “.png”, “.gif”]:
image_files.extend(glob.glob(os.path.join(source_dir, “*” + ext)))
各ファイルをデスティネーションディレクトリにコピー
for file_path in image_files:
try:
shutil.copy2(file_path, destination_dir) # copy2はメタデータもコピー
print(f”{file_path} を {destination_dir} にコピーしました”)
except Exception as e:
print(f”{file_path} のコピーに失敗しました: {e}”)
“`
この例では、images ディレクトリにあるすべての .jpg, .png, .gif ファイルを processed_images ディレクトリにコピーしています。 shutil.copy2() 関数は、ファイルのメタデータもコピーします。os.path.join を使用してパスを安全に結合しています。
例2: 特定のパターンに一致するファイル名を変更する
“`python
import glob
import os
import re
対象ディレクトリを指定
target_dir = “files”
ファイル名に “old_” が含まれるファイルを検索
old_files = glob.glob(os.path.join(target_dir, “old_“))
ファイル名を変更
for file_path in old_files:
try:
# 新しいファイル名を生成 (“old_” を削除)
new_file_name = re.sub(r”old_”, “”, os.path.basename(file_path))
new_file_path = os.path.join(target_dir, new_file_name)
# ファイル名を変更
os.rename(file_path, new_file_path)
print(f"{file_path} を {new_file_path} に変更しました")
except Exception as e:
print(f"{file_path} の名前変更に失敗しました: {e}")
“`
この例では、files ディレクトリにあるファイル名に “old_” が含まれるファイルを検索し、”old_” を削除した新しいファイル名に変更しています。 os.path.basename() 関数は、ファイルパスからファイル名のみを抽出します。 re.sub() 関数は、正規表現を使って文字列を置換します。
9. glob モジュールのパフォーマンス
globモジュールは、ファイルシステムを直接操作するため、パフォーマンスに影響を与える可能性があります。特に、大規模なファイルシステムで recursive=True を指定した場合、検索に時間がかかることがあります。
パフォーマンスを改善するためには、以下の点に注意してください。
- できるだけ具体的なglobパターンを使用する。
recursive=Trueの使用を最小限にする。glob.iglob()を使用して、イテレータで処理する。- マルチスレッドやマルチプロセッシングを使って、並列処理を行う。
10. まとめ
この記事では、Pythonのglobモジュールを使って、特定の拡張子を持つファイルを抽出する方法について詳細に解説しました。globモジュールは、ワイルドカード文字を使って柔軟なパターンマッチングを実現し、ファイルシステムから特定の条件に合致するファイルを効率的に検索できます。基本的な使い方から、複数の拡張子を指定する方法、サブディレクトリを再帰的に検索する方法、大文字・小文字を区別しない検索、pathlibモジュールとの連携、エラーハンドリング、実践的な例、パフォーマンスに関する注意点まで、幅広くカバーしました。
globモジュールを使いこなすことで、ファイル操作の効率を大幅に向上させ、様々なプログラミングタスクをより簡単にこなせるようになります。この記事が、あなたのPythonスキル向上に役立つことを願っています。 今後も、globモジュールを活用して、より効率的なファイル操作を実現してください。