215 votes

Comment faire une recherche récursive dans un sous-dossier et retourner les fichiers dans une liste ?

Je travaille sur un script pour parcourir récursivement les sous-dossiers d'un dossier principal et construire une liste à partir d'un certain type de fichier. J'ai un problème avec le script. Il est actuellement configuré comme suit :

for root, subFolder, files in os.walk(PATH):
    for item in files:
        if item.endswith(".txt") :
            fileNamePath = str(os.path.join(root,subFolder,item))

le problème est que le subFolder extrait une liste de sous-dossiers plutôt que le dossier dans lequel se trouve le fichier ITEM. Je pensais exécuter une boucle for pour le sous-dossier avant et rejoindre la première partie du chemin d'accès, mais je me suis dit que je devais vérifier si quelqu'un avait des suggestions avant cela.

12voto

LastTigerEyes Points 517

Votre solution originale était presque correcte, mais la variable "Root" est dynamiquement mise à jour lors de son parcours récursif. os.walk() est un générateur récursif. Chaque ensemble de tuple (Root, subFolder, files) correspond à une Root spécifique de la manière dont vous l'avez configuré.

c'est-à-dire

root = 'C:\\'
subFolder = ['Users', 'ProgramFiles', 'ProgramFiles (x86)', 'Windows', ...]
files = ['foo1.txt', 'foo2.txt', 'foo3.txt', ...]

root = 'C:\\Users\\'
subFolder = ['UserAccount1', 'UserAccount2', ...]
files = ['bar1.txt', 'bar2.txt', 'bar3.txt', ...]

...

J'ai fait une légère modification de votre code pour imprimer une liste complète.

import os
for root, subFolder, files in os.walk(PATH):
    for item in files:
        if item.endswith(".txt") :
            fileNamePath = str(os.path.join(root,item))
            print(fileNamePath)

J'espère que cela vous aidera !

EDIT : (basé sur les retours d'expérience)

L'OP a mal compris/mal étiqueté la variable subFolder, car elle est en réalité Tous les sous-dossiers dans "Root". . À cause de cela, OP, vous essayez de faire os.path.join(str, list, str), ce qui ne fonctionne probablement pas comme vous le pensiez.

Pour plus de clarté, vous pouvez essayer ce système d'étiquetage :

import os
for current_dir_path, current_subdirs, current_files in os.walk(RECURSIVE_ROOT):
    for aFile in current_files:
        if aFile.endswith(".txt") :
            txt_file_path = str(os.path.join(current_dir_path, aFile))
            print(txt_file_path)

9voto

dermen Points 2798

Ce n'est pas la réponse la plus pythique, mais je la mets ici pour le plaisir parce que c'est une belle leçon de récursion.

def find_files( files, dirs=[], extensions=[]):
    new_dirs = []
    for d in dirs:
        try:
            new_dirs += [ os.path.join(d, f) for f in os.listdir(d) ]
        except OSError:
            if os.path.splitext(d)[1] in extensions:
                files.append(d)

    if new_dirs:
        find_files(files, new_dirs, extensions )
    else:
        return

Sur ma machine, j'ai deux dossiers, root y root2

mender@multivax ]ls -R root root2
root:
temp1 temp2

root/temp1:
temp1.1 temp1.2

root/temp1/temp1.1:
f1.mid

root/temp1/temp1.2:
f.mi  f.mid

root/temp2:
tmp.mid

root2:
dummie.txt temp3

root2/temp3:
song.mid

Disons que je veux trouver tous les .txt et tout .mid dans l'un ou l'autre de ces répertoires, alors je peux simplement faire

files = []
find_files( files, dirs=['root','root2'], extensions=['.mid','.txt'] )
print(files)

#['root2/dummie.txt',
# 'root/temp2/tmp.mid',
# 'root2/temp3/song.mid',
# 'root/temp1/temp1.1/f1.mid',
# 'root/temp1/temp1.2/f.mid']

9voto

WilliamCanin Points 101

Vous pouvez le faire de cette façon pour vous retourner une liste de fichiers à chemin absolu.

def list_files_recursive(path):
    """
    Function that receives as a parameter a directory path
    :return list_: File List and Its Absolute Paths
    """

    import os

    files = []

    # r = root, d = directories, f = files
    for r, d, f in os.walk(path):
        for file in f:
            files.append(os.path.join(r, file))

    lst = [file for file in files]
    return lst

if __name__ == '__main__':

    result = list_files_recursive('/tmp')
    print(result)

4voto

prosti Points 4630

La récursivité est une nouveauté de Python 3.5, elle ne fonctionnera donc pas avec Python 2.7. Voici l'exemple qui utilise r Il suffit donc de fournir le chemin tel quel sur Win, Lin, ...

import glob

mypath=r"C:\Users\dj\Desktop\nba"

files = glob.glob(mypath + r'\**\*.py', recursive=True)
# print(files) # as list
for f in files:
    print(f) # nice looking single line per file

Note : Il listera tous les fichiers, quelle que soit la profondeur à laquelle il doit aller.

4voto

Yossarian42 Points 161

Cette fonction va récursivement mettre seulement les fichiers dans une liste.

import os

def ls_files(dir):
    files = list()
    for item in os.listdir(dir):
        abspath = os.path.join(dir, item)
        try:
            if os.path.isdir(abspath):
                files = files + ls_files(abspath)
            else:
                files.append(abspath)
        except FileNotFoundError as err:
            print('invalid directory\n', 'Error: ', err)
    return files

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