Dapatkan daftar file yang difilter dalam direktori


281

Saya mencoba untuk mendapatkan daftar file dalam direktori menggunakan Python, tetapi saya tidak ingin daftar SEMUA file.

Apa yang saya inginkan pada dasarnya adalah kemampuan untuk melakukan sesuatu seperti yang berikut tetapi menggunakan Python dan tidak mengeksekusi ls.

ls 145592*.jpg

Jika tidak ada metode bawaan untuk ini, saya saat ini sedang berpikir untuk menulis perulangan for untuk mengulangi hasil dari os.listdir()dan untuk menambahkan semua file yang cocok ke daftar baru.

Namun, ada banyak file di direktori itu dan oleh karena itu saya berharap ada metode yang lebih efisien (atau metode bawaan).


[Tautan ini mungkin membantu Anda :) Dapatkan daftar file yang disaring dalam direktori] ( codereview.stackexchange.com/a/33642 )
sha111

Perhatikan bahwa Anda mungkin harus berhati-hati tentang penyortiran pesanan jika ini penting untuk aplikasi Anda.
lumbric

Jawaban:


385

21
Oh, saya baru saja memperhatikan bahwa dokumen Python mengatakan glob () "dilakukan dengan menggunakan fungsi os.listdir () dan fnmatch.fnmatch () dalam konser, dan bukan dengan benar-benar memanggil subkulit". Dengan kata lain, glob () tidak memiliki peningkatan efisiensi yang mungkin diharapkan.
Ben Hoyt

5
Ada satu perbedaan utama: glob.glob('145592*.jpg')mencetak seluruh jalur absolut file sementara ls 145592*.jpghanya mencetak daftar file.
Ébe Isaac

8
@ Ben Mengapa meminta subkulit (subproses) memiliki peningkatan efisiensi?
Paulo Neves

7
@PauloNeves: benar, komentar saya di atas juga tidak masuk akal bagi saya 7 tahun kemudian. :-) Saya kira saya merujuk pada fakta bahwa glob()hanya menggunakan listdir + fnmatch, daripada panggilan sistem operasi khusus untuk melakukan penyaringan wildcard. Sebagai contoh, pada Windows FindFirstFileAPI memungkinkan Anda untuk menentukan wildcard sehingga OS melakukan penyaringan secara langsung, dan mungkin lebih efisien (saya tidak berpikir ada yang setara di Linux).
Ben Hoyt

1
@ Marsh: Seperti biasa, direktori kerja proses saat ini.
Ignacio Vazquez-Abrams

125

glob.glob()jelas merupakan cara untuk melakukannya (sesuai Ignacio). Namun, jika Anda membutuhkan pencocokan yang lebih rumit, Anda dapat melakukannya dengan pemahaman daftar dan re.match(), seperti:

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

Lebih fleksibel, tetapi seperti yang Anda perhatikan, kurang efisien.


Ini jelas terlihat lebih kuat. Misalnya, harus melakukan sesuatu seperti[0-9]+
demongolem

3
Ya, jelas lebih kuat - namun fnmatch mendukung [0123456789]urutan ( lihat dokumen ), dan juga memiliki fnmatch.filter()fungsi yang membuat loop ini sedikit lebih efisien.
Ben Hoyt

49

Sederhana saja:

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)]

Saya lebih suka bentuk pemahaman daftar ini karena bacaannya baik dalam bahasa Inggris.

Saya membaca baris keempat sebagai: Untuk setiap fn di os.listdir untuk jalur saya, beri saya hanya yang cocok dengan salah satu ekstensi saya yang disertakan.

Mungkin sulit bagi programmer python pemula untuk benar-benar terbiasa menggunakan daftar pemahaman untuk penyaringan, dan dapat memiliki beberapa overhead memori untuk set data yang sangat besar, tetapi untuk daftar direktori dan tugas penyaringan string sederhana lainnya, daftar pemahaman mengarah ke lebih bersih kode yang dapat didokumentasikan.

Satu-satunya hal tentang desain ini adalah bahwa itu tidak melindungi Anda dari membuat kesalahan dengan melewatkan string daripada daftar. Misalnya, jika Anda secara tidak sengaja mengonversi string ke daftar dan berakhir dengan mengecek semua karakter string, Anda bisa mendapatkan banyak positif palsu.

Tetapi lebih baik memiliki masalah yang mudah diperbaiki daripada solusi yang sulit dimengerti.


5
Bukan berarti ada kebutuhan untuk di any()sini, karena str.endswith()mengambil urutan akhir. if fn.endswith(included_extentensions)lebih dari cukup.
Martijn Pieters

3
Terlepas dari ketidakefisienan tidak menggunakan str.endswith(seq)Martijn menunjukkan, ini tidak benar, karena file harus diakhiri dengan .extitu untuk memiliki ekstensi itu. Kode ini juga akan menemukan (misalnya) file bernama "myjpg" atau direktori yang bernama "png". Untuk memperbaikinya, cukup awali setiap ekstensi included_extensionsdengan ..
Ben Hoyt

Saya selalu sedikit waspada terhadap kode dalam jawaban yang jelas belum dijalankan atau tidak dapat dijalankan. Variabel included_extensionsvs included_extentsions? Sayang sekali karena kalau tidak ini adalah jawaban yang saya sukai.
Auspice


17

Filter dengan globmodul:

Impor bola

import glob

Kartu Liar:

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']

Ekstensi Fiter .txt:

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

Satu karakter

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

Rentang angka

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

Alphabet Ranges

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

12

Kode awal

import glob
import fnmatch
import pathlib
import os

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

Solusi 1 - gunakan "glob"

# lookup in current dir
glob.glob(pattern)

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

Solusi 2 - gunakan "os" + "fnmatch"

Varian 2.1 - Pencarian dalam direktori saat ini

# 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']

Varian 2.2 - Pencarian rekursif

# 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))

Hasil

./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

Solusi 3 - gunakan "pathlib"

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

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

Catatan:

  1. Diuji pada Python 3.4
  2. Modul "pathlib" ditambahkan hanya dalam Python 3.4
  3. Python 3.5 menambahkan fitur untuk pencarian rekursif dengan glob.glob https://docs.python.org/3.5/library/glob.html#glob.glob . Karena mesin saya diinstal dengan Python 3.4, saya belum mengujinya.

9

gunakan os.walk untuk mendaftarkan file Anda secara rekursif

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)

Tidak perlu diiris; file.endswith(alist_filter)cukup.
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")]

Ini akan memberi Anda daftar file jpg dengan path lengkapnya. Anda dapat mengganti x[0]+"/"+fdengan fhanya untuk nama file. Anda juga dapat mengganti f.endswith(".jpg")dengan kondisi string apa pun yang Anda inginkan.


3

Anda mungkin juga menyukai pendekatan tingkat tinggi (saya telah mengimplementasikan dan mengemasnya sebagai 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

dapat diinstal dengan

pip install findtools

2

Nama file dengan ekstensi "jpg" dan "png" di "path / ke / gambar":

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

Ini sangat mirip dengan jawaban yang diberikan oleh @ ramsey0
chb

1

Anda dapat menggunakan pathlib yang tersedia di pustaka standar Python 3.4 dan di atasnya.

from pathlib import Path

files = [f for f in Path.cwd().iterdir() if f.match("145592*.jpg")]

1

Anda dapat menentukan pola dan memeriksanya. Di sini saya telah mengambil kedua pola awal dan akhir dan mencari mereka dalam nama file. FILES berisi daftar semua file dalam direktori.

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

Bagaimana dengan str.split ()? Tidak ada yang diimpor.

import os

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

2
Ini sangat mirip dengan jawaban pemberian oleh @gypsy
Sushanth

Ini tampaknya mirip dengan jawaban @ ramsey0 menggunakan f.endswith('.jpg')(tetapi juga akan memilih filename.jpg.ext)
anjsimmo

-1

Anda dapat menggunakan subprocess.check_ouput () sebagai

import subprocess

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

Tentu saja, string di antara tanda kutip dapat berupa apa pun yang ingin Anda jalankan di shell, dan menyimpan hasilnya.


Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.