ディレクトリ内のファイルのフィルタリングされたリストを取得する


281

Pythonを使用してディレクトリ内のファイルのリストを取得しようとしていますが、すべてのファイルのリストが必要ではありません。

私が本質的に望んでいるのは、次のようなことをする能力ですが、Pythonを使用し、lsを実行しません。

ls 145592*.jpg

このための組み込みメソッドがない場合、私は現在、forループを記述して、結果を繰り返し処理しos.listdir()、一致するすべてのファイルを新しいリストに追加することを考えています。

ただし、そのディレクトリには多くのファイルがあるため、より効率的な方法(または組み込みの方法)があることを願っています。


[このリンクが役立つ場合があります:)ディレクトリ内のファイルのフィルターされたリストを取得します](codereview.stackexchange.com/a/33642
sha111

これがアプリケーションにとって重要な場合は、ソート順に特別な注意を払う場合があることに注意してください。
lumbric

回答:


385

21
ああ、Pythonのドキュメントでglob()が「os.listdir()関数とfnmatch.fnmatch()関数を組み合わせて使用​​し、実際にサブシェルを呼び出すのではなく)と言っていることに気づきました。言い換えると、glob()には、期待されるような効率の改善がありません。
Ben Hoyt、

5
主な違いは1つあります。glob.glob('145592*.jpg')ファイルの絶対パス全体をls 145592*.jpg出力し、ファイルのリストのみを出力します。
EBEアイザック

8
@Benサブシェル(サブプロセス)を呼び出すと、効率が向上するのはなぜですか?
Paulo Neves 2017年

7
@PauloNeves:確かに、上記の私のコメントは7年後も私には意味がありません。:-)私はglob()、ワイルドカードフィルタリングを行うために、特別なオペレーティングシステムコールではなく、listdir + fnmatchのみを使用するという事実を参照していたと思います。たとえば、WindowsではFindFirstFileAPIを使用してワイルドカードを指定できるため、OSは直接、おそらくはより効率的にフィルタリングを行います(Linuxには同等のものはないと思います)。
Ben Hoyt 2017年

1
@marsh:いつものように、プロセスの現在の作業ディレクトリ。
Ignacio Vazquez-Abrams

124

glob.glob()間違いなくそれを行う方法です(Ignacioによる)。ただし、より複雑な照合が必要な場合は、リスト内包表記とを使用してre.match()、次のように行うことができます。

files = [f for f in os.listdir('.') if re.match(r'[0-9]+.*\.jpg', f)]

柔軟性は高くなりますが、お気づきのとおり、効率が低下します。


これは間違いなくより強力なようです。たとえば、次のようなことをしなければならない[0-9]+
demongolem

3
はい、間違いなくより強力です-ただし、fnmatchは[0123456789]シーケンスをサポートし(docsを参照)、fnmatch.filter()このループをわずかに効率的にする機能も備えています。
Ben Hoyt 2013年

49

単純にする:

import os
relevant_path = "[path to folder]"
included_extensions = ['jpg','jpeg', 'bmp', 'png', 'gif']
file_names = [fn for fn in os.listdir(relevant_path)
              if any(fn.endswith(ext) for ext in included_extensions)]

これは英語でよく読めるので、この形式のリスト内包表記を好みます。

私は4行目を次のように読みます:os.listdirの各fnのパスについて、含まれている拡張機能のいずれかに一致するもののみを提供します。

初心者のPythonプログラマーがフィルタリングにリスト内包表記を実際に使用することに慣れるのは難しいかもしれませんが、非常に大きなデータセットの場合はメモリオーバーヘッドがいくらか発生する可能性がありますドキュメント化可能なコード。

このデザインの唯一の点は、リストではなく文字列を渡すというミスを防ぐことができないことです。たとえば、誤って文字列をリストに変換し、最終的に文字列のすべての文字をチェックしてしまうと、多くの誤検知が発生する可能性があります。

しかし、理解するのが難しい解決策よりも、修正が容易な問題がある方が良いです。


5
エンディングのシーケンスをとるany()ので、ここで何か必要があるというわけではありません。十分すぎるほどです。str.endswith()if fn.endswith(included_extentensions)
Martijn Pieters

3
str.endswith(seq)Martijnが指摘したことを使用しないことの非効率性は別として、ファイル.extがその拡張子を持つためには、ファイルで終わる必要があるため、これは正しくありません。このコードは、(たとえば)「myjpg」というファイルまたは「png」という名前のディレクトリも検索します。修正するには、各拡張子の前にをincluded_extensions付けます.
Ben Hoyt

明らかに実行されていない、または実行できない回答のコードには常に少し警戒しています。変数included_extensionsvs included_extentsions?それ以外の場合はこれが私の好ましい答えであるため、残念です。
Auspice


17

globモジュールでフィルター:

グロブをインポート

import glob

ワイルドカード:

files=glob.glob("data/*")
print(files)

Out:

['data/ks_10000_0', 'data/ks_1000_0', 'data/ks_100_0', 'data/ks_100_1',
'data/ks_100_2', 'data/ks_106_0', 'data/ks_19_0', 'data/ks_200_0', 'data/ks_200_1', 
'data/ks_300_0', 'data/ks_30_0', 'data/ks_400_0', 'data/ks_40_0', 'data/ks_45_0', 
'data/ks_4_0', 'data/ks_500_0', 'data/ks_50_0', 'data/ks_50_1', 'data/ks_60_0', 
'data/ks_82_0', 'data/ks_lecture_dp_1', 'data/ks_lecture_dp_2']

フィッターエクステンション.txt

files = glob.glob("/home/ach/*/*.txt")

単一の文字

glob.glob("/home/ach/file?.txt")

番号範囲

glob.glob("/home/ach/*[0-9]*")

アルファベット範囲

glob.glob("/home/ach/[a-c]*")

12

暫定コード

import glob
import fnmatch
import pathlib
import os

pattern = '*.py'
path = '.'

解決策1-「glob」を使用する

# lookup in current dir
glob.glob(pattern)

In [2]: glob.glob(pattern)
Out[2]: ['wsgi.py', 'manage.py', 'tasks.py']

解決策2-「os」+「fnmatch」を使用します

バリアント2.1-現在のディレクトリでの検索

# lookup in current dir
fnmatch.filter(os.listdir(path), pattern)

In [3]: fnmatch.filter(os.listdir(path), pattern)
Out[3]: ['wsgi.py', 'manage.py', 'tasks.py']

バリアント 2.2-再帰的なルックアップ

# lookup recursive
for dirpath, dirnames, filenames in os.walk(path):

    if not filenames:
        continue

    pythonic_files = fnmatch.filter(filenames, pattern)
    if pythonic_files:
        for file in pythonic_files:
            print('{}/{}'.format(dirpath, file))

結果

./wsgi.py
./manage.py
./tasks.py
./temp/temp.py
./apps/diaries/urls.py
./apps/diaries/signals.py
./apps/diaries/actions.py
./apps/diaries/querysets.py
./apps/library/tests/test_forms.py
./apps/library/migrations/0001_initial.py
./apps/polls/views.py
./apps/polls/formsets.py
./apps/polls/reports.py
./apps/polls/admin.py

解決策3-「pathlib」を使用する

# lookup in current dir
path_ = pathlib.Path('.')
tuple(path_.glob(pattern))

# lookup recursive
tuple(path_.rglob(pattern))

ノート:

  1. Python 3.4でテスト済み
  2. モジュール「pathlib」はPython 3.4でのみ追加されました
  3. Python 3.5では、glob.glob https://docs.python.org/3.5/library/glob.html#glob.globを使用した再帰的なルックアップ機能が追加されました 。私のマシンにはPython 3.4がインストールされているため、テストしていません。

9

os.walkを使用してファイルを再帰的に一覧表示する

import os
root = "/home"
pattern = "145992"
alist_filter = ['jpg','bmp','png','gif'] 
path=os.path.join(root,"mydir_to_scan")
for r,d,f in os.walk(path):
    for file in f:
        if file[-3:] in alist_filter and pattern in file:
            print os.path.join(root,file)

スライスする必要はありません。file.endswith(alist_filter)十分です
Martijn Pieters

5
import os

dir="/path/to/dir"
[x[0]+"/"+f for x in os.walk(dir) for f in x[2] if f.endswith(".jpg")]

これにより、完全なパスを含むjpgファイルのリストが表示されます。あなたは置き換えることができますx[0]+"/"+ff、単にファイル名のために。またf.endswith(".jpg")、任意の文字列条件に置き換えることもできます。


3

より高レベルのアプローチが好きかもしれません(私はfindtoolsとして実装してパッケージ化しました):

from findtools.find_files import (find_files, Match)


# Recursively find all *.txt files in **/home/**
txt_files_pattern = Match(filetype='f', name='*.txt')
found_files = find_files(path='/home', match=txt_files_pattern)

for found_file in found_files:
    print found_file

でインストールできます

pip install findtools

2

「path / to / images」に「jpg」と「png」の拡張子が付いたファイル名:

import os
accepted_extensions = ["jpg", "png"]
filenames = [fn for fn in os.listdir("path/to/images") if fn.split(".")[-1] in accepted_extensions]



1

パターンを定義して確認できます。ここでは、開始パターンと終了パターンの両方を取り、ファイル名でそれらを探しています。FILESには、ディレクトリ内のすべてのファイルのリストが含まれています。

import os
PATTERN_START = "145592"
PATTERN_END = ".jpg"
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
for r,d,FILES in os.walk(CURRENT_DIR):
    for FILE in FILES:
        if PATTERN_START in FILE and PATTERN_END in FILE:
            print FILE

0

str.split()はどうですか?インポートするものはありません。

import os

image_names = [f for f in os.listdir(path) if len(f.split('.jpg')) == 2]

2
これは、@ gypsy
Sushanth

これは@ ramsey0の回答と似ているようですf.endswith('.jpg')(ただし、も選択されますfilename.jpg.ext
anjsimmo

-1

次のようにsubprocess.check_ouput()を使用できます

import subprocess

list_files = subprocess.check_output("ls 145992*.jpg", shell=True) 

もちろん、引用符で囲まれた文字列は、シェルで実行して出力を保存したいものであれば何でもかまいません。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.