Obtenir une liste de tous les sous-répertoires du répertoire courant

Réponses:

604

Voulez-vous dire des sous-répertoires immédiats ou tous les répertoires dans l'arborescence?

Dans les deux cas, vous pouvez utiliser os.walkpour cela:

os.walk(directory)

produira un tuple pour chaque sous-répertoire. La première entrée du triplet est un nom de répertoire, donc

[x[0] for x in os.walk(directory)]

devrait vous donner tous les sous-répertoires, récursivement.

Notez que la deuxième entrée du tuple est la liste des répertoires enfants de l'entrée en première position, vous pouvez donc l'utiliser à la place, mais il est peu probable que vous économisiez beaucoup.

Cependant, vous pouvez l'utiliser uniquement pour vous donner les répertoires enfants immédiats:

next(os.walk('.'))[1]

Ou consultez les autres solutions déjà publiées, en utilisant os.listdiret os.path.isdir, y compris celles de " Comment obtenir tous les sous-répertoires immédiats en Python ".

Blair Conrad
la source
7
Je pense que os.walk renvoie des triplets (racine, répertoires, fichiers). Ce qui signifie que dirs a de nombreuses entrées répétitives. Existe-t-il un moyen plus efficace de se reproduire dans les répertoires?
mathtick
22
N'utilisez pas os.walk('.').next()[1]ou os.walk('.').__next__()[1]directement. À la place, utilisez la fonction intégrée next(), qui est disponible à la fois dans Python 2 (voir doc) et Python 3 (voir doc) . Par exemple: next(os.walk('.'))[1].
Lucio Paiva
1
@Lucio Pourquoi est-il mauvais d'utiliser os.walk('.').next()[1]directement?
wisbucky
8
@wisbucky, c'est une mauvaise pratique car il iteraror.__next__()s'agit d'une méthode interne et l' iterator.next()utilisation doit être transférée vers la fonction intégrée next()selon PEP-3114. Voir PEP-3114 qui a été approuvé en 2007.
Lucio Paiva
16
Pour toute personne préoccupée par les différences de performances entre les solutions + os.walket os.listdir+ os.path.isdir: je viens de tester sur un répertoire avec 10 000 sous-répertoires (avec des millions de fichiers dans la hiérarchie ci-dessous) et les différences de performances sont négligeables. os.walk: "10 boucles, meilleur de 3: 44,6 msec par boucle" et os.listdir+ os.path.isdir: "10 boucles, meilleur de 3: 45,1 msec par boucle"
kevinmicke
165
import os

d = '.'
[os.path.join(d, o) for o in os.listdir(d) 
                    if os.path.isdir(os.path.join(d,o))]
gahooa
la source
5
notez que dans cette approche, vous devez vous occuper des problèmes d'abspath s'ils ne sont pas exécutés sur '.'
daspostloch
4
Juste un avertissement, si vous n'utilisez pas le cwd ('.'), Cela ne fonctionnera pas sauf si vous faites un os.path.joinon opour obtenir le chemin complet, sinon isdir(0)retournera toujours faux
James McMahon
5
Il semble que l'article ait été mis à jour avec des correctifs pour les deux problèmes mentionnés ci-dessus.
cgmb
1
Pour éviter d'appeler os.path.joindeux fois, vous pouvez d'abord rejoindre puis filtrer la liste en utilisant os.path.isdir: filter(os.path.isdir, [os.path.join(d, o) for o in os.listdir(d)])
quant_dev
155

Vous pouvez simplement utiliser glob.glob

from glob import glob
glob("/path/to/directory/*/")

N'oubliez pas le suivi /après le *.

Udit Bansal
la source
Agréable. Facile. Seulement, il laisse la queue /dans les noms
juanmirocks
9
Si vous ne pouvez pas supposer /être le séparateur de dossiers, procédez comme glob(os.path.join(path_to_directory, "*", ""))
suit
1
Cela ne fonctionne pas pour les sous-répertoires! Pour utiliser glob, voici la réponse complète: utiliser un Glob () pour rechercher des fichiers de manière récursive en Python?
poppie
1
pour rendre glob récursif, vous pouvez simplement ajouter l'argument suivantrecursive=True
JacoSolari
102

Beaucoup plus agréable que ci-dessus, car vous n'avez pas besoin de plusieurs os.path.join () et vous obtiendrez le chemin complet directement (si vous le souhaitez), vous pouvez le faire en Python 3.5 et supérieur.

subfolders = [ f.path for f in os.scandir(folder) if f.is_dir() ]

Cela donnera le chemin d'accès complet au sous-répertoire. Si vous souhaitez uniquement utiliser le nom du sous-répertoire f.nameau lieu def.path

https://docs.python.org/3/library/os.html#os.scandir


Légèrement OT: Si vous avez besoin de tous les sous-dossiers de manière récursive et / ou de tous les fichiers récursivement , jetez un œil à cette fonction, qui est plus rapide que os.walk& globet renverra une liste de tous les sous-dossiers ainsi que tous les fichiers à l'intérieur de ces (sous-) sous-dossiers: https://stackoverflow.com/a/59803793/2441026

Si vous ne souhaitez que tous les sous-dossiers de manière récursive :

def fast_scandir(dirname):
    subfolders= [f.path for f in os.scandir(dirname) if f.is_dir()]
    for dirname in list(subfolders):
        subfolders.extend(fast_scandir(dirname))
    return subfolders

Renvoie une liste de tous les sous-dossiers avec leurs chemins d'accès complets. C'est encore plus rapide que os.walket beaucoup plus rapide que glob.


Une analyse de toutes les fonctions

tl; dr:
- Si vous souhaitez obtenir tous les sous - répertoires immédiats pour une utilisation de dossier os.scandir.
- Si vous souhaitez obtenir tous les sous-répertoires, même imbriqués , utilisez os.walkou - un peu plus vite - la fast_scandirfonction ci-dessus.
- Ne jamais utiliser os.walkuniquement pour les sous-répertoires de niveau supérieur, car cela peut être des centaines (!) Fois plus lent que os.scandir.

  • Si vous exécutez le code ci-dessous, assurez-vous de l'exécuter une fois pour que votre système d'exploitation ait accédé au dossier, jetez les résultats et exécutez le test, sinon les résultats seront vissés.
  • Vous voudrez peut-être mélanger les appels de fonction, mais je l'ai testé, et cela n'a pas vraiment d'importance.
  • Tous les exemples donneront le chemin d'accès complet au dossier. L'exemple pathlib en tant qu'objet Path (Windows).
  • Le premier élément de os.walksera le dossier de base. Vous n'aurez donc pas que des sous-répertoires. Vous pouvez utiliser fu.pop(0)pour le supprimer.
  • Aucun des résultats n'utilisera le tri naturel . Cela signifie que les résultats seront triés comme suit: 1, 10, 2. Pour obtenir un tri naturel (1, 2, 10), veuillez consulter https://stackoverflow.com/a/48030307/2441026


Résultats :

os.scandir      took   1 ms. Found dirs: 439
os.walk         took 463 ms. Found dirs: 441 -> it found the nested one + base folder.
glob.glob       took  20 ms. Found dirs: 439
pathlib.iterdir took  18 ms. Found dirs: 439
os.listdir      took  18 ms. Found dirs: 439

Testé avec W7x64, Python 3.8.1.

# -*- coding: utf-8 -*-
# Python 3


import time
import os
from glob import glob
from pathlib import Path


directory = r"<insert_folder>"
RUNS = 1


def run_os_walk():
    a = time.time_ns()
    for i in range(RUNS):
        fu = [x[0] for x in os.walk(directory)]
    print(f"os.walk\t\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found dirs: {len(fu)}")


def run_glob():
    a = time.time_ns()
    for i in range(RUNS):
        fu = glob(directory + "/*/")
    print(f"glob.glob\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found dirs: {len(fu)}")


def run_pathlib_iterdir():
    a = time.time_ns()
    for i in range(RUNS):
        dirname = Path(directory)
        fu = [f for f in dirname.iterdir() if f.is_dir()]
    print(f"pathlib.iterdir\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found dirs: {len(fu)}")


def run_os_listdir():
    a = time.time_ns()
    for i in range(RUNS):
        dirname = Path(directory)
        fu = [os.path.join(directory, o) for o in os.listdir(directory) if os.path.isdir(os.path.join(directory, o))]
    print(f"os.listdir\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found dirs: {len(fu)}")


def run_os_scandir():
    a = time.time_ns()
    for i in range(RUNS):
        fu = [f.path for f in os.scandir(directory) if f.is_dir()]
    print(f"os.scandir\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms.\tFound dirs: {len(fu)}")


if __name__ == '__main__':
    run_os_scandir()
    run_os_walk()
    run_glob()
    run_pathlib_iterdir()
    run_os_listdir()
user136036
la source
35

Si vous avez besoin d'une solution récursive qui trouvera tous les sous-répertoires dans les sous-répertoires, utilisez walk comme proposé précédemment.

Si vous n'avez besoin que des répertoires enfants du répertoire actuel, combinez-les os.listdiravecos.path.isdir

Eli Bendersky
la source
23

Implémenté cela en utilisant python-os-walk. ( http://www.pythonforbeginners.com/code-snippets-source-code/python-os-walk/ )

import os

print("root prints out directories only from what you specified")
print("dirs prints out sub-directories from root")
print("files prints out all files from root and directories")
print("*" * 20)

for root, dirs, files in os.walk("/var/log"):
    print(root)
    print(dirs)
    print(files)
Charith De Silva
la source
19

Vous pouvez obtenir la liste des sous-répertoires (et fichiers) dans Python 2.7 en utilisant os.listdir (chemin)

import os
os.listdir(path)  # list of subdirectories and files
Oscar Martin
la source
59
Cela inclut également les fichiers.
Tarnay Kálmán
2
Le nom prête à confusion car «dir» ne fait pas référence aux objets formant la liste mais au répertoire du conteneur. Veuillez vérifier vos réponses sur une ligne, pour les débutants, il est très tentant de les sélectionner.
Titou
4
Méfiez-vous de cette os.listdirliste des contenus du répertoire, y compris les fichiers.
guneysus
13

Répertorier uniquement les répertoires

print("\nWe are listing out only the directories in current directory -")
directories_in_curdir = filter(os.path.isdir, os.listdir(os.curdir))
print(directories_in_curdir)

Liste uniquement les fichiers dans le répertoire courant

files = filter(os.path.isfile, os.listdir(os.curdir))
print("\nThe following are the list of all files in the current directory -")
print(files)
NutJobb
la source
2
N'a pas fonctionné sur mac OS. Je pense que le problème est que os.listdir ne renvoie que le nom du répertoire et non le chemin complet mais os.path.isdir ne renvoie True que si le chemin complet est un répertoire.
denson
Cela fonctionne en dehors du répertoire courant si vous modifiez légèrement la ligne: subdirs = filter (os.path.isdir, [os.path.join (dir, x) pour x dans os.listdir (dir)])
RLC
12

Python 3.4 a introduit le pathlibmodule dans la bibliothèque standard, qui fournit une approche orientée objet pour gérer les chemins du système de fichiers:

from pathlib import Path

p = Path('./')

# List comprehension
[f for f in p.iterdir() if f.is_dir()]

# The trailing slash to glob indicated directories
# This will also include the current directory '.'
list(p.glob('**/'))

Pathlib est également disponible sur Python 2.7 via le module pathlib2 sur PyPi.

joelostblom
la source
Pour parcourir la liste des sous-répertoires, voici une belle syntaxe épurée:for f in filter(Path.is_dir, p.iterdir()):
Bryan Roach
11

Depuis que je suis tombé sur ce problème en utilisant les chemins Python 3.4 et Windows UNC, voici une variante pour cet environnement:

from pathlib import WindowsPath

def SubDirPath (d):
    return [f for f in d.iterdir() if f.is_dir()]

subdirs = SubDirPath(WindowsPath(r'\\file01.acme.local\home$'))
print(subdirs)

Pathlib est nouveau dans Python 3.4 et facilite beaucoup l'utilisation des chemins sous différents systèmes d'exploitation: https://docs.python.org/3.4/library/pathlib.html

Marcus Schommler
la source
10

Bien qu'il soit répondu à cette question il y a longtemps. Je veux recommander d'utiliser le pathlibmodule car c'est un moyen robuste de travailler sur Windows et Unix OS.

Donc, pour obtenir tous les chemins dans un répertoire spécifique, y compris les sous-répertoires:

from pathlib import Path
paths = list(Path('myhomefolder', 'folder').glob('**/*.txt'))

# all sorts of operations
file = paths[0]
file.name
file.stem
file.parent
file.suffix

etc.

Joost Döbken
la source
9

Merci du conseil les gars. J'ai rencontré un problème avec les liens logiciels (récursion infinie) renvoyés sous forme de répertoires. Liens souples? Nous ne voulons pas de liens mous puants! Donc...

Cela n'a rendu que les répertoires, pas les liens logiciels:

>>> import os
>>> inf = os.walk('.')
>>> [x[0] for x in inf]
['.', './iamadir']
KurtB
la source
1
Comment [x[0] for x in inf]s'appelle- t-on en python pour que je puisse le rechercher?
shinzou
2
@shinzou C'est une compréhension de liste. Super utile. Recherchez également les compréhensions dict.
KurtB
9

Copier coller convivial dans ipython:

import os
d='.'
folders = list(filter(lambda x: os.path.isdir(os.path.join(d, x)), os.listdir(d)))

Sortie de print(folders):

['folderA', 'folderB']
Andrew Schreiber
la source
2
Qu'est-ce que X dans ce cas?
Abhishek Parikh
1
@AbhishekParikh xest l'élément de la liste créé par os.listdir(d)car listdirretournera les fichiers et dossiers avec lesquels il utilise la filtercommande os.path.isdirpour filtrer tous les fichiers de la liste.
James Burke
8

Voilà comment je le fais.

    import os
    for x in os.listdir(os.getcwd()):
        if os.path.isdir(x):
            print(x)
Mujeeb Ishaque
la source
Ça ne marche pas. Je suppose qu'en x, vous devez fournir un chemin complet pour vérifier en utilisant isdir ()
niranjan patidar
Vous rencontrez probablement des problèmes avec os.getcwd (); Essentiellement, vous pouvez obtenir le chemin absolu et l'utiliser à la place. dir = os.path.dirname (os.path.abspath ( fichier ))
Mujeeb Ishaque
en utilisant os, pat.join () a fonctionné pour moi. Parce que cela a aidé à obtenir le chemin complet du sous-répertoire.
niranjan patidar
7

Voici quelques fonctions simples basées sur l'exemple de @Blair Conrad -

import os

def get_subdirs(dir):
    "Get a list of immediate subdirectories"
    return next(os.walk(dir))[1]

def get_subfiles(dir):
    "Get a list of immediate subfiles"
    return next(os.walk(dir))[2]
Brian Burns
la source
6

En s'appuyant sur la solution d'Eli Bendersky, utilisez l'exemple suivant:

import os
test_directory = <your_directory>
for child in os.listdir(test_directory):
    test_path = os.path.join(test_directory, child)
    if os.path.isdir(test_path):
        print test_path
        # Do stuff to the directory "test_path"

<your_directory>est le chemin d'accès au répertoire que vous souhaitez parcourir.

Blairg23
la source
5

Avec le chemin complet et comptable pour être de chemin ., .., \\, ..\\..\\subfolder, etc:

import os, pprint
pprint.pprint([os.path.join(os.path.abspath(path), x[0]) \
    for x in os.walk(os.path.abspath(path))])
DevPlayer
la source
4

Cette réponse ne semblait pas déjà exister.

directories = [ x for x in os.listdir('.') if os.path.isdir(x) ]
Andy
la source
7
Cela retournera toujours une liste vide si vous recherchez autre chose que le répertoire de travail actuel, ce qui est techniquement ce que l'OP cherche à faire, mais pas très réutilisable.
ochawkeye
2
répertoires = [x pour x dans os.listdir (localDir) si os.path.isdir (localDir + x)
Poonam
3

J'ai eu une question similaire récemment, et j'ai découvert que la meilleure réponse pour python 3.6 (comme l'ajout d'un havlock utilisateur) est d'utiliser os.scandir. Puisqu'il semble qu'il n'y ait pas de solution en l'utilisant, j'ajouterai la mienne. Tout d'abord, une solution non récursive qui répertorie uniquement les sous-répertoires directement sous le répertoire racine.

def get_dirlist(rootdir):

    dirlist = []

    with os.scandir(rootdir) as rit:
        for entry in rit:
            if not entry.name.startswith('.') and entry.is_dir():
                dirlist.append(entry.path)

    dirlist.sort() # Optional, in case you want sorted directory names
    return dirlist

La version récursive ressemblerait à ceci:

def get_dirlist(rootdir):

    dirlist = []

    with os.scandir(rootdir) as rit:
        for entry in rit:
            if not entry.name.startswith('.') and entry.is_dir():
                dirlist.append(entry.path)
                dirlist += get_dirlist(entry.path)

    dirlist.sort() # Optional, in case you want sorted directory names
    return dirlist

gardez à l'esprit que vous entry.pathutilisez le chemin absolu vers le sous-répertoire. Si vous n'avez besoin que du nom du dossier, vous pouvez utiliser à la entry.nameplace. Reportez-vous à os.DirEntry pour plus de détails sur l' entryobjet.

Alberto A
la source
En fait, la façon dont cela est écrit ne fonctionnera pas sur 3.5, seulement 3.6. Pour utiliser sur 3.5, vous devez supprimer le gestionnaire de contexte - voir stackoverflow.com/questions/41401417/…
havlock
C'est correct. Je pourrais jurer avoir lu quelque part que le gestionnaire de contexte a été implémenté en 3.5, mais il semble que je me trompe.
Alberto A
1

utiliser une fonction de filtre os.path.isdirsur os.listdir() quelque chose comme çafilter(os.path.isdir,[os.path.join(os.path.abspath('PATH'),p) for p in os.listdir('PATH/')])

oneLeggedChicken
la source
1

Cela répertoriera tous les sous-répertoires dans l'arborescence des fichiers.

import pathlib


def list_dir(dir):
    path = pathlib.Path(dir)
    dir = []
    try:
        for item in path.iterdir():
            if item.is_dir():
                dir.append(item)
                dir = dir + list_dir(item)
        return dir
    except FileNotFoundError:
        print('Invalid directory')

pathlib est nouveau dans la version 3.4

Yossarian42
la source
1

Fonction pour renvoyer une liste de tous les sous-répertoires d'un chemin de fichier donné. Recherche dans toute l'arborescence des fichiers.

import os

def get_sub_directory_paths(start_directory, sub_directories):
    """
    This method iterates through all subdirectory paths of a given 
    directory to collect all directory paths.

    :param start_directory: The starting directory path.
    :param sub_directories: A List that all subdirectory paths will be 
        stored to.
    :return: A List of all sub-directory paths.
    """

    for item in os.listdir(start_directory):
        full_path = os.path.join(start_directory, item)

        if os.path.isdir(full_path):
            sub_directories.append(full_path)

            # Recursive call to search through all subdirectories.
            get_sub_directory_paths(full_path, sub_directories)

return sub_directories
Matthew Ashley
la source
1

nous pouvons obtenir la liste de tous les dossiers en utilisant os.walk ()

import os

path = os.getcwd()

pathObject = os.walk(path)

ce pathObject est un objet et nous pouvons obtenir un tableau par

arr = [x for x in pathObject]

arr is of type [('current directory', [array of folder in current directory], [files in current directory]),('subdirectory', [array of folder in subdirectory], [files in subdirectory]) ....]

Nous pouvons obtenir la liste de tous les sous-répertoires en parcourant l' arr et en imprimant le tableau du milieu

for i in arr:
   for j in i[1]:
      print(j)

Cela imprimera tout le sous-répertoire.

Pour obtenir tous les fichiers:

for i in arr:
   for j in i[2]:
      print(i[0] + "/" + j)
Shivam Kesarwani
la source
0

Cette fonction, avec un parent donné, directoryitère sur tous ses éléments directoriesrécursifs et printstout filenamesce qu'elle trouve à l'intérieur. Trop utile.

import os

def printDirectoryFiles(directory):
   for filename in os.listdir(directory):  
        full_path=os.path.join(directory, filename)
        if not os.path.isdir(full_path): 
            print( full_path + "\n")


def checkFolders(directory):

    dir_list = next(os.walk(directory))[1]

    #print(dir_list)

    for dir in dir_list:           
        print(dir)
        checkFolders(directory +"/"+ dir) 

    printDirectoryFiles(directory)       

main_dir="C:/Users/S0082448/Desktop/carpeta1"

checkFolders(main_dir)


input("Press enter to exit ;")
dbz
la source
0

En rejoignant plusieurs solutions d'ici, voici ce que j'ai fini par utiliser:

import os
import glob

def list_dirs(path):
    return [os.path.basename(x) for x in filter(
        os.path.isdir, glob.glob(os.path.join(path, '*')))]
SadSeven
la source