128 votes

Os.walk sans fouiller dans les répertoires ci-dessous

Comment limiter os.walk pour ne renvoyer que les fichiers dans le répertoire que je lui donne ?

def _dir_list(self, dir_name, whitelist):
    outputList = []
    for root, dirs, files in os.walk(dir_name):
        for f in files:
            if os.path.splitext(f)[1] in whitelist:
                outputList.append(os.path.join(root, f))
            else:
                self._email_to_("ignorer")
    return outputList

3 votes

Un autre cas où la multitude d'approches possibles et tous les avertissements qui les accompagnent suggèrent que cette fonctionnalité devrait être ajoutée à la bibliothèque standard Python.

0 votes

files_with_full_path = [f.path for f in os.scandir(dir) if f.is_file()]. Si vous avez seulement besoin des noms de fichiers utilisez f.name au lieu de f.path. C'est la solution la plus rapide et beaucoup plus rapide que n'importe quelle walk ou listdir, voir stackoverflow.com/a/40347279/2441026.

236voto

Yuval Adam Points 59423

Ne pas utiliser os.walk.

Exemple :

import os

root = "C:\\"
for item in os.listdir(root):
    if os.path.isfile(os.path.join(root, item)):
        print item

2 votes

@576i: cela ne fait pas la différence entre les fichiers et les répertoires

4 votes

@Alexandr os.path.isfile et os.path.isdir vous permettent de faire la différence. Je ne comprends pas, car os.path.isfile est dans le code d'exemple depuis '08 et votre commentaire est de '16. C'est clairement la meilleure réponse, car vous ne cherchez pas à parcourir un répertoire, mais à le lister.

0 votes

@DanielF, ce que je voulais dire ici, c'est que vous devez boucler sur tous les éléments, tandis que walk vous donne immédiatement les listes séparées de dossiers et de fichiers.

112voto

nosklo Points 75862

Utilisez la fonction walklevel.

import os

def walklevel(some_dir, level=1):
    some_dir = some_dir.rstrip(os.path.sep)
    assert os.path.isdir(some_dir)
    num_sep = some_dir.count(os.path.sep)
    for root, dirs, files in os.walk(some_dir):
        yield root, dirs, files
        num_sep_this = root.count(os.path.sep)
        if num_sep + level <= num_sep_this:
            del dirs[:]

Cela fonctionne exactement comme os.walk, mais vous pouvez lui passer un paramètre level qui indique la profondeur de la récursion.

3 votes

Est-ce que cette fonction "parcourt" réellement toute la structure puis supprime les entrées en dessous d'un certain point ? Ou est-ce qu'il y a quelque chose de plus astucieux qui se passe ? Je ne suis même pas sûr de comment vérifier cela avec du code. --débutant en Python

1 votes

@mathtick : lorsque qu'un répertoire situé au niveau souhaité ou en dessous est trouvé, tous ses sous-répertoires sont supprimés de la liste des sous-répertoires à rechercher ensuite. Ainsi, ils ne seront pas "parcourus".

2 votes

Je viens de faire un +1 à cela parce que j'avais du mal à savoir comment "supprimer" des répertoires. J'avais essayé dirs = [] et dirs = None mais cela n'a pas fonctionné. map(dirs.remove, dirs) a fonctionné, mais avec quelques messages non désirés '[None]' imprimés. Donc, pourquoi del dirs[:] spécifiquement?

63voto

Pieter Points 11

Je pense que la solution est en réalité très simple.

utilise

break

pour ne faire que la première itération de la boucle for, il doit y avoir une manière plus élégante.

for root, dirs, files in os.walk(dir_name):
    for f in files:
        ...
        ...
    break
...

La première fois que vous appelez os.walk, il renvoie des tuples pour le répertoire actuel, puis à la prochaine itération le contenu du répertoire suivant.

Prenez le script original et ajoutez simplement un break.

def _dir_list(self, dir_name, whitelist):
    outputList = []
    for root, dirs, files in os.walk(dir_name):
        for f in files:
            if os.path.splitext(f)[1] in whitelist:
                outputList.append(os.path.join(root, f))
            else:
                self._email_to_("ignore")
        break
    return outputList

10 votes

Ce devrait être la réponse acceptée. Il suffit d'ajouter un "break" après la boucle "for f in files" pour arrêter la récursivité. Vous voudrez peut-être aussi vous assurer que topdown=True.

0 votes

Je veux juste ajouter ce commentaire et vous dire merci de m'avoir fait gagner du temps au travail en donnant une réponse aussi simple et efficace.

27voto

Alex Coventry Points 11090

La suggestion d'utiliser listdir est bonne. La réponse directe à votre question en Python 2 est root, dirs, files = os.walk(dir_name).next().

La syntaxe équivalente en Python 3 est root, dirs, files = next(os.walk(dir_name))

1 votes

Oh, je recevais toutes sortes d'erreurs amusantes de celui-là. ValueError: trop de valeurs à déballer

1 votes

Bien! On dirait un hack, cependant. Comme lorsque vous allumez un moteur mais que vous ne le laissez faire qu'une révolution, puis tirez sur la clé pour le laisser mourir.

0 votes

Je suis tombé là-dessus; root, dirs, files = os.walk(dir_name).next() me donne AttributeError: 'generator' object has no attribute 'next'

15voto

Greg Hewgill Points 356191

Vous pourriez utiliser os.listdir() qui renvoie une liste de noms (pour les fichiers et les répertoires) dans un répertoire donné. Si vous avez besoin de distinguer les fichiers des répertoires, appelez os.stat() sur chaque nom.

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