333 votes

Obtenir une liste filtrée de fichiers dans un répertoire

J'essaie d'obtenir une liste de fichiers dans un répertoire en utilisant Python, mais je ne veux pas une liste de TOUS les fichiers.

Ce que je veux essentiellement, c'est pouvoir faire quelque chose comme ce qui suit, mais en utilisant Python et sans exécuter ls.

ls 145592*.jpg

S'il n'y a pas de méthode intégrée pour cela, je pense actuellement à écrire une boucle for pour itérer à travers les résultats d'un os.listdir() et d'ajouter tous les fichiers correspondants à une nouvelle liste.

Cependant, il y a beaucoup de fichiers dans ce répertoire et j'espère donc qu'il existe une méthode plus efficace (ou une méthode intégrée).

0 votes

[Ce lien pourrait vous aider :) Obtenir une liste filtrée des fichiers d'un répertoire ]( codereview.stackexchange.com/a/33642 )

0 votes

Notez que vous pouvez apporter un soin particulier à l'ordre de tri si cela est important pour votre application.

460voto

Ignacio Vazquez-Abrams Points 312628
import glob

jpgFilenamesList = glob.glob('145592*.jpg')

Ver glob dans la documentation python

24 votes

Oh, je viens de remarquer que les docs Python disent que glob() "est fait en utilisant les fonctions os.listdir() et fnmatch.fnmatch() de concert, et non en invoquant réellement un sous-shell". En d'autres termes, glob() ne présente pas les améliorations d'efficacité auxquelles on pourrait s'attendre.

5 votes

Il y a une différence principale : glob.glob('145592*.jpg') imprime le chemin absolu complet des fichiers tandis que ls 145592*.jpg imprime uniquement la liste des fichiers.

8 votes

@Ben Pourquoi le fait d'invoquer un sous-shell (sous-processus) permettrait-il d'améliorer l'efficacité ?

148voto

Ben Hoyt Points 2719

glob.glob() est définitivement la façon de faire (selon Ignacio). Cependant, si vous avez besoin d'une correspondance plus compliquée, vous pouvez le faire avec une compréhension de liste et re.match() quelque chose comme ça :

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

Plus flexible, mais comme vous le notez, moins efficace.

1 votes

Cela semble définitivement plus puissant. Par exemple, avoir à faire quelque chose comme [0-9]+

3 votes

Oui, définitivement plus puissant -- cependant fnmatch supporte [0123456789] séquences ( voir docs ), et il dispose également de la fnmatch.filter() qui rend cette boucle légèrement plus efficace.

71voto

ramsey0 Points 39

Restez simple :

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

Je préfère cette forme de compréhension de liste car elle se lit bien en anglais.

Je lis la quatrième ligne comme : Pour chaque fn dans os.listdir pour mon chemin, donnez-moi seulement ceux qui correspondent à l'une de mes extensions incluses.

Il peut être difficile pour les programmeurs python novices de s'habituer à l'utilisation des compréhensions de listes pour le filtrage, et il peut y avoir une surcharge de mémoire pour les très grands ensembles de données, mais pour lister un répertoire et d'autres tâches simples de filtrage de chaînes, les compréhensions de listes conduisent à un code plus propre et documentable.

Le seul inconvénient de cette conception est qu'elle ne vous protège pas contre l'erreur de passer une chaîne de caractères au lieu d'une liste. Par exemple, si vous convertissez accidentellement une chaîne de caractères en liste et que vous vous retrouvez à vérifier tous les caractères d'une chaîne de caractères, vous risquez d'obtenir un grand nombre de faux positifs.

Mais il est préférable d'avoir un problème facile à résoudre qu'une solution difficile à comprendre.

6 votes

Non pas qu'il y ait un quelconque besoin de any() ici, parce que str.endswith() prend un séquence de fin. if fn.endswith(included_extentensions) est plus que suffisant.

3 votes

En dehors de l'inefficacité de ne pas utiliser str.endswith(seq) que Martijn a signalé, ce n'est pas correct, car un fichier doit se terminer par .ext pour qu'il ait cette extension. Ce code trouvera également (par exemple) un fichier appelé "myjpg" ou un répertoire nommé simplement "png". Pour corriger cela, il suffit de préfixer chaque extension dans included_extensions avec un . .

0 votes

Je me méfie toujours un peu du code dans les réponses qui n'a manifestement pas été exécuté ou ne peut pas l'être. La variable included_extensions vs included_extentsions ? Dommage, car sinon c'est la réponse que je préfère.

10voto

ghostdog74 Points 86060

Utiliser os.walk pour lister récursivement vos fichiers

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)

0 votes

Pas besoin de trancher ; file.endswith(alist_filter) est suffisant.

0 votes

Nous devons utiliser any(file.endswith(filter) for filter in alist_filter) como endswith() n'autorise pas la liste comme paramètre.

4voto

Yauhen Yakimovich Points 2222

Vous pourriez aussi aimer une approche plus haut niveau (j'ai implémenté et emballé en tant que 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

peut être installé avec

pip install findtools

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X