Ottenere un elenco di tutte le sottodirectory nella directory corrente


Risposte:


604

Intendi le sottodirectory immediate o ogni directory in fondo all'albero?

In entrambi i casi, è possibile utilizzare os.walkper fare questo:

os.walk(directory)

produrrà una tupla per ogni sottodirectory. La prima voce nella 3-tupla è un nome di directory, quindi

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

dovrebbe darti tutte le sottodirectory, in modo ricorsivo.

Nota che la seconda voce nella tupla è la lista delle directory secondarie della voce nella prima posizione, quindi puoi usarla invece, ma non è probabile che ti salvi molto.

Tuttavia, potresti usarlo solo per darti le directory secondarie immediate:

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

Oppure vedi le altre soluzioni già pubblicate, usando os.listdire os.path.isdir, comprese quelle in " Come ottenere tutte le sottodirectory immediate in Python ".


7
Penso che os.walk ritorni triple (root, dirs, file). Ciò significa che dirs ha molte voci ripetute. C'è un modo più efficiente che ricorre attraverso le directory?
mathtick,

22
Non utilizzare os.walk('.').next()[1]o os.walk('.').__next__()[1]direttamente. Invece, usa la funzione integrata next(), che è disponibile sia in Python 2 (vedi doc) che in Python 3 (vedi doc) . Ad esempio: next(os.walk('.'))[1].
Lucio Paiva,

1
@Lucio Perché è male usare os.walk('.').next()[1]direttamente?
Wisbucky,

8
@wisbucky è una cattiva pratica perché iteraror.__next__()è un metodo interno e l' iterator.next()utilizzo dovrebbe essere trasferito nell'integrato next()secondo PEP-3114. Vedi PEP-3114 che è stato approvato nel 2007.
Lucio Paiva,

16
Per chiunque sia preoccupato per le differenze di prestazioni tra os.walke os.listdir+ os.path.isdirsoluzioni: ho appena testato su una directory con 10.000 sottodirectory (con milioni di file nella gerarchia di seguito) e le differenze di prestazioni sono trascurabili. os.walk: "10 loop, meglio di 3: 44.6 msec per loop" e os.listdir+ os.path.isdir: "10 loop, meglio di 3: 45.1 msec per loop"
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))]

5
nota che in questo approccio devi occuparti dei problemi di abspath se non eseguito su '.'
daspostloch,

4
Solo un avvertimento, se non stai usando il cwd ('.'), Questo non funzionerà se non fai un os.path.joinon oper ottenere il percorso completo, altrimenti isdir(0)tornerà sempre falso
James McMahon

5
Sembra che il post sia stato aggiornato con correzioni per i due problemi menzionati sopra.
cgmb,

1
Per evitare di chiamare os.path.joindue volte, puoi prima unirti e poi filtrare l'elenco usando os.path.isdir: filter(os.path.isdir, [os.path.join(d, o) for o in os.listdir(d)])
quant_dev

155

Potresti semplicemente usare glob.glob

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

Non dimenticare il finale /dopo il *.


Bello. Semplice. Solo, lascia il trailing /nei nomi
juanmirocks il

9
Se non puoi assumere /di essere il separatore di cartelle, procedi come segue:glob(os.path.join(path_to_directory, "*", ""))
juanmirocks

1
Questo non funziona per le sottodirectory! Per usare glob ecco la risposta completa: utilizzare un Glob () per trovare i file in modo ricorsivo in Python?
Poppie,

1
per rendere ricorsivo glob è sufficiente aggiungere il seguente argomentorecursive=True
JacoSolari,

102

Molto più bello di quanto sopra, perché non hai bisogno di diversi os.path.join () e otterrai il percorso completo direttamente (se lo desideri), puoi farlo in Python 3.5 e versioni successive.

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

Ciò fornirà il percorso completo alla sottodirectory. Se vuoi solo il nome della sottodirectory usa f.nameinvece dif.path

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


Leggermente OT: Nel caso in cui avete bisogno di tutte le sottocartelle in modo ricorsivo e / o tutti i file in modo ricorsivo , hanno uno sguardo a questa funzione, che è più veloce di os.walk& globe restituirà un elenco di tutte le sottocartelle e tutti i file all'interno di queste (sotto) sottocartelle: https://stackoverflow.com/a/59803793/2441026

Nel caso in cui si desideri ricorsivamente solo tutte le sottocartelle :

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

Restituisce un elenco di tutte le sottocartelle con i loro percorsi completi. Questo è ancora più veloce di os.walke molto più veloce di glob.


Un'analisi di tutte le funzioni

tl; dr:
- Se vuoi ottenere tutte le sottodirectory immediate per una cartella, usa os.scandir.
- Se vuoi ottenere tutte le sottodirectory, anche quelle nidificate , usa os.walko - leggermente più veloce - la fast_scandirfunzione sopra.
- Non utilizzare mai os.walksolo per le sottodirectory di livello superiore, poiché può essere centinaia (!) Volte più lenta di os.scandir.

  • Se si esegue il codice riportato di seguito, assicurarsi di eseguirlo una volta in modo che il sistema operativo abbia avuto accesso alla cartella, scartare i risultati ed eseguire il test, altrimenti i risultati verranno rovinati.
  • Potresti voler confondere le chiamate di funzione, ma l'ho testato e non ha davvero importanza.
  • Tutti gli esempi forniranno il percorso completo della cartella. L'esempio pathlib come oggetto Path (Windows).
  • Il primo elemento di os.walksarà la cartella di base. Quindi non otterrai solo le sottodirectory. Puoi usarlo fu.pop(0)per rimuoverlo.
  • Nessuno dei risultati utilizzerà l'ordinamento naturale . Ciò significa che i risultati verranno ordinati in questo modo: 1, 10, 2. Per ottenere l'ordinamento naturale (1, 2, 10), dai un'occhiata a https://stackoverflow.com/a/48030307/2441026


Risultati :

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

Testato con 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()

35

Se hai bisogno di una soluzione ricorsiva che troverà tutte le sottodirectory nelle sottodirectory, usa walk come proposto prima.

Se hai solo bisogno delle directory figlio della directory corrente, combinale os.listdirconos.path.isdir




19

Puoi ottenere l'elenco delle sottodirectory (e dei file) in Python 2.7 usando os.listdir (percorso)

import os
os.listdir(path)  # list of subdirectories and files

59
Questo include anche i file.
Tarnay Kálmán,

2
Il nome è confuso in quanto 'dir' non si riferisce agli oggetti che compongono l'elenco ma alla directory del contenitore. Controlla le risposte a una riga, per i principianti è molto allettante selezionarle.
Titou,

4
Attenzione a che os.listdirelenca i contenuti della directory inclusi i file.
guneiso

13

Elenco delle sole directory

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)

Elencare solo i file nella directory corrente

files = filter(os.path.isfile, os.listdir(os.curdir))
print("\nThe following are the list of all files in the current directory -")
print(files)

2
Non ha funzionato su mac OS. Penso che il problema sia che os.listdir restituisce solo il nome della directory e non il percorso completo ma os.path.isdir restituisce True solo se il percorso completo è una directory.
denson,

Funziona al di fuori della directory corrente se si modifica leggermente la riga: subdirs = filter (os.path.isdir, [os.path.join (dir, x) per x in os.listdir (dir)])
RLC

12

Python 3.4 ha introdotto il pathlibmodulo nella libreria standard, che fornisce un approccio orientato agli oggetti per gestire i percorsi del filesystem:

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 è disponibile anche su Python 2.7 tramite il modulo pathlib2 su PyPi.


Per scorrere l'elenco delle sottodirectory, ecco una sintassi bella e chiara:for f in filter(Path.is_dir, p.iterdir()):
Bryan Roach,

11

Dal momento che mi sono imbattuto in questo problema utilizzando i percorsi UNC di Python 3.4 e Windows, ecco una variante per questo ambiente:

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 è una novità di Python 3.4 e semplifica notevolmente l'utilizzo di percorsi con diversi sistemi operativi: https://docs.python.org/3.4/library/pathlib.html


10

Sebbene questa domanda abbia una risposta molto tempo fa. Voglio raccomandare di usare ilpathlib modulo poiché questo è un modo affidabile per lavorare su Windows e sistemi operativi Unix.

Quindi, per ottenere tutti i percorsi in una directory specifica comprese le sottodirectory:

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

eccetera.


9

Grazie per i suggerimenti, ragazzi. Ho riscontrato un problema con i softlink (ricorsione infinita) che venivano restituiti come dir. Softlink? Non vogliamo collegamenti soft puzzolenti! Così...

Questo ha reso solo le directory, non i softlink:

>>> import os
>>> inf = os.walk('.')
>>> [x[0] for x in inf]
['.', './iamadir']

1
Cosa viene [x[0] for x in inf]chiamato in Python in modo che io possa cercarlo?
shinzou,

2
@shinzou Questa è una comprensione dell'elenco. Super utile. Cerca anche le comprensioni del dettato.
KurtB,

9

Copia incolla amichevole in ipython:

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

Uscita da print(folders):

['folderA', 'folderB']

2
Che cos'è X in questo caso?
Abhishek Parikh,

1
@AbhishekParikh xè l'elemento dall'elenco creato da os.listdir(d)perché listdirrestituirà i file e le cartelle con cui sta usando il filtercomando os.path.isdirper filtrare tutti i file dall'elenco.
James Burke,

8

Questo è come lo faccio.

    import os
    for x in os.listdir(os.getcwd()):
        if os.path.isdir(x):
            print(x)

Non funziona Immagino che in x devi fornire il percorso completo per controllare usando isdir ()
niranjan patidar

Probabilmente stai riscontrando problemi con os.getcwd (); In sostanza, quello che puoi fare è ottenere il percorso assoluto e usarlo invece. dir = os.path.dirname (os.path.abspath ( file ))
Mujeeb Ishaque

usando os, pat.join () ha funzionato per me. Perché ha aiutato a ottenere il percorso completo della sottodirectory.
niranjan patidar

7

Ecco un paio di semplici funzioni basate sull'esempio di @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]

6

Basandosi sulla soluzione di Eli Bendersky, utilizzare il seguente esempio:

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"

dove si <your_directory>trova il percorso della directory che si desidera attraversare.


5

Con il percorso completo e la contabilità per essere percorso ., .., \\, ..\\..\\subfolder, ecc:

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

4

Questa risposta non sembra esistere già.

directories = [ x for x in os.listdir('.') if os.path.isdir(x) ]

7
Questo restituirà sempre un elenco vuoto se stai cercando qualcosa di diverso dalla directory di lavoro corrente, che è tecnicamente ciò che l'OP sta cercando di fare, ma non molto riutilizzabile.
ochawkeye,

2
directory = [x per x in os.listdir (localDir) se os.path.isdir (localDir + x)
Poonam

3

Di recente ho fatto una domanda simile e ho scoperto che la migliore risposta per python 3.6 (come ha aggiunto l'havlock dell'utente) è usare os.scandir. Dal momento che sembra che non ci sia soluzione usando, aggiungerò il mio. Innanzitutto, una soluzione non ricorsiva che elenca solo le sottodirectory direttamente nella directory principale.

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 versione ricorsiva sarebbe simile a questa:

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

tieni presente che entry.pathesercita il percorso assoluto verso la sottodirectory. Nel caso in cui sia necessario solo il nome della cartella, è possibile utilizzare entry.nameinvece. Fare riferimento a os.DirEntry per ulteriori dettagli entrysull'oggetto.


In realtà, il modo in cui è scritto non funzionerà su 3.5, solo 3.6. Per utilizzare il 3.5 è necessario rimuovere direttore contesto - vedi stackoverflow.com/questions/41401417/...
Havlock

Questo è corretto. Potrei giurare di aver letto da qualche parte che il gestore del contesto è stato implementato in 3.5, ma sembra che mi sbagli.
Alberto A

1

usa una funzione di filtro os.path.isdirsu os.listdir() qualcosa del generefilter(os.path.isdir,[os.path.join(os.path.abspath('PATH'),p) for p in os.listdir('PATH/')])


1

Questo elencherà tutte le sottodirectory lungo l'albero dei file.

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 è nuovo nella versione 3.4


1

Funzione per restituire un elenco di tutte le sottodirectory all'interno di un determinato percorso di file. Cercherà attraverso l'intero albero dei file.

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

1

possiamo ottenere l'elenco di tutte le cartelle utilizzando os.walk ()

import os

path = os.getcwd()

pathObject = os.walk(path)

this pathObject è un oggetto e possiamo ottenere un array da

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

Siamo in grado di ottenere l'elenco di tutta la sottodirectory ripetendo l' arr e stampando l'array centrale

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

Questo stamperà tutta la sottodirectory.

Per ottenere tutti i file:

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

0

Questa funzione, con un determinato genitore, directoryscorre su tutto il suo directoriesmodo ricorsivo e printstutto filenamesciò che trova all'interno. Troppo 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 ;")

0

Unendo più soluzioni da qui, questo è quello che ho finito per usare:

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, '*')))]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.