pythonでディレクトリの中からファイルの一覧を取得して、一括でファイルを移動したり、コピーしたり、色々な用途でファイルを操作することがあると思います。
そこでディレクトリからファイルの一覧を取得する方法説明します。
os.listdir() を使う方法
まずは osモジュールの os.listdir() を使ってファイルの一覧を取得する方法です。
使用例
[test] というディレクトリの中に、次のようなファイルがあったとしてファイル名の一覧を取得するには
<実装例>
import os
path = "./test" # ディレクトリのパス
# 実行時のパスと同一階層にtestディレクトリを作ったため"./"としてます
fileList = os.listdir(path) # ファイル名一覧を取得
print(fileList) # 出力
<結果>
['a.txt', 'b.jpg', 'c.png']
特定の拡張子のファイルだけ取得したい場合
os.listdir() はディレクトリの中の全てを取得するため、特定の拡張子のファイル名だけを取り出したい場合は、ファイル名の一覧から endswith() を使って拡張子を判定してファイル名を抽出してあげればOKです。
なお、endswith() は指定した文字で終わるかどうかを判定するメソッドです。
<実装例>
import os
path = "./test" # ディレクトリのパス
fileList = os.listdir(path) # ファイル名一覧を取得
targetList = [f for f in fileList if f.endswith('.txt')] # 拡張子が".txt" のファイル名を抽出
print(targetList) # 出力
<結果>
['a.txt']
なお、上記の抽出部分 [f for f in fileList if f.endswith(‘.txt’)] は「リスト内包表記」を使って書きましたが、次のコードと同じ意味です。
targetList = [] # 空のリストを作る
for file in fileList: # ファイル名一覧から一つずつファイル名を取得
if file.endswith('.txt'): # 拡張子が ".txt"かどうか
targetList.append(file) # リストに追加
「リスト内包表記」は簡潔に書けますが、意味が分からなくなるときがあるので、こっちの方が個人的にはしっくりきますね。
複数の拡張子を指定したいとき
複数の拡張子を指定したいときは、ifの条件を追加してあげればOKです。
targetList = [f for f in fileList if f.endswith('.txt') or f.endswith('.png')] # ".txt"と".png"を抽出
print(targetList) # 出力
<結果>
['a.txt', 'c.png']
glob.glob()を使う方法
globモジュールの glob.glob() を使い、指定したパターンに一致するファイルパスを取得する方法です。個人的には os.listdir() より簡単に拡張子を指定して抽出できるのでこちらを使うことが多いです。
使用例
指定したディレクトリの全てのファイルの一覧を取得する場合は、glob() メソッドの引数に”*”(ワイルドカード)を指定します。
import glob
fileList = glob.glob('./test/*') # 全てのファイルを抽出
print(fileList)
<結果>
['a.txt', 'b.jpg', 'c.png']
特定の拡張子のファイルだけ取得したい場合
引数の”*”(ワイルドカード)の後に取得したい拡張子を付けるだけでOKです。
import glob
fileList = glob.glob('./test/*.txt') # .txtのみを抽出
print(fileList)
<結果>
['a.txt']
複数の拡張子を指定したいとき
例えば前述したように endswith() を使って拡張子を判定する方法や、re.search() の正規表現を使って抽出する方法など、色々やり方はあると思いますが、何個も指定がないのであれば、こんなやり方でも良いと思います。
import glob
fileList = glob.glob('./test/*.txt') # .txtのみを抽出
fileList.extend(glob.glob('./test/*.png')) # .pngのみを抽出してリストに追加
print(fileList)
<結果>
['a.txt', 'c.png']
下の階層のディレクトリのファイルまで取得したいとき
上の例でglob() メソッドで “/test/*.txt” と指定しても、指定したディレクトリの同一階層にある”a.txt”しか取得できません。
そこで glob()メソッドの引数に“recursive=True”を追加して、パターンに”**”を追加することで、下位のディレクトリも含めた全てのファイルから取得することができます。
import glob
fileList = glob.glob('./test/**/*.txt', recursive=True) # test以下の全てのtxtファイルを抽出
print(fileList)
<結果>
['a.txt', 'test/d.txt', 'test/e.txt']
取得したリストはファイル名ではなくファイルパスになるため、 os.path.basename() を組み合わせてファイル名だけ取得することもできます。
import glob
fileList = [os.path.basename(x) for x in glob.glob('**\*.txt', recursive=True)]
print(fileList)
<結果>
['a.txt', 'd.txt', 'e.txt']