Obtener una lista de todos los subdirectorios en el directorio actual

Respuestas:

604

¿Te refieres a subdirectorios inmediatos, o cada directorio en el árbol?

De cualquier manera, podría usar os.walkpara hacer esto:

os.walk(directory)

producirá una tupla para cada subdirectorio. La primera entrada en la 3-tupla es un nombre de directorio, entonces

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

debería darle todos los subdirectorios, de forma recursiva.

Tenga en cuenta que la segunda entrada en la tupla es la lista de directorios secundarios de la entrada en la primera posición, por lo que podría usar esto en su lugar, pero no es probable que le ahorre mucho.

Sin embargo, puede usarlo solo para darle los directorios secundarios inmediatos:

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

O vea las otras soluciones ya publicadas, utilizando os.listdire os.path.isdir, incluidas las de " Cómo obtener todos los subdirectorios inmediatos en Python ".

Blair Conrad
fuente
77
Creo que os.walk devuelve triples (raíz, directorios, archivos). Lo que significa que dirs tiene muchas entradas repetidas. ¿Hay una manera más eficiente que se repite a través de directorios?
mathtick
22
No utilizar os.walk('.').next()[1]o os.walk('.').__next__()[1]directamente. En su lugar, use la función incorporada next(), que está disponible tanto en Python 2 (consulte el documento) como en Python 3 (consulte el documento) . Por ejemplo: next(os.walk('.'))[1].
Lucio Paiva
1
@Lucio ¿Por qué es malo usarlo os.walk('.').next()[1]directamente?
wisbucky
8
@wisbucky es una mala práctica porque iteraror.__next__()es un método interno y el iterator.next()uso debe pasar a la versión incorporada de next()acuerdo con PEP-3114. Ver PEP-3114 que fue aprobado en 2007.
Lucio Paiva
16
Para cualquier persona preocupada por las diferencias de rendimiento entre os.walky os.listdir+ os.path.isdirsoluciones: acabo de probar en un directorio con 10,000 subdirectorios (con millones de archivos en la jerarquía a continuación) y las diferencias de rendimiento son insignificantes. os.walk: "10 bucles, mejor de 3: 44,6 ms por bucle" y os.listdir+ os.path.isdir: "10 bucles, mejor de 3: 45,1 ms por bucle"
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
fuente
55
tenga en cuenta que en este enfoque debe ocuparse de los problemas de abspath si no se ejecuta en '.'
daspostloch
44
Solo un aviso, si no está utilizando el cwd ('.'), Esto no funcionará a menos que haga un os.path.joinencendido opara obtener el camino completo, de lo contrario isdir(0)siempre devolverá falso
James McMahon
55
Parece que la publicación se ha actualizado con correcciones para los dos problemas mencionados anteriormente.
cgmb
1
Para evitar llamar os.path.joindos veces, primero puede unirse y luego filtrar la lista usando os.path.isdir: filter(os.path.isdir, [os.path.join(d, o) for o in os.listdir(d)])
quant_dev
155

Podrías usar glob.glob

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

No olvides el final /después del *.

Udit Bansal
fuente
Agradable. Simple. Solo, deja el final /en los nombres
juanmirocks
99
Si no se puede asumir /que es el separador de carpetas, haga lo siguiente:glob(os.path.join(path_to_directory, "*", ""))
juanmirocks
1
¡Esto no funciona para subdirectorios! Para usar glob, esta es la respuesta completa: ¿ Usar un Glob () para buscar archivos de forma recursiva en Python?
poppie
1
para hacer que el globo sea recursivo solo puede agregar el siguiente argumentorecursive=True
JacoSolari
102

Mucho mejor que lo anterior, ya que no necesita varios os.path.join () y obtendrá la ruta completa directamente (si lo desea), puede hacerlo en Python 3.5 y superior.

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

Esto le dará la ruta completa al subdirectorio. Si solo desea el nombre del subdirectorio, use en f.namelugar def.path

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


Ligeramente OT: en caso de que necesite todas las subcarpetas recursivamente y / o todos los archivos recursivamente , eche un vistazo a esta función, que es más rápida que os.walk& globy devolverá una lista de todas las subcarpetas, así como todos los archivos dentro de esas (sub) subcarpetas: https://stackoverflow.com/a/59803793/2441026

En caso de que desee solo todas las subcarpetas de forma recursiva :

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

Devuelve una lista de todas las subcarpetas con sus rutas completas. De nuevo, esto es más rápido que os.walky mucho más rápido que glob.


Un análisis de todas las funciones.

tl; dr:
- Si desea obtener todos los subdirectorios inmediatos para un uso de carpeta os.scandir.
- Si desea obtener todos los subdirectorios, incluso los anidados , use os.walko, un poco más rápido, la fast_scandirfunción anterior.
- Nunca lo use os.walksolo para subdirectorios de nivel superior, ya que puede ser cientos (!) De veces más lento que os.scandir.

  • Si ejecuta el código a continuación, asegúrese de ejecutarlo una vez para que su sistema operativo haya accedido a la carpeta, descarte los resultados y ejecute la prueba, de lo contrario los resultados se atornillarán.
  • Es posible que desee mezclar las llamadas de función, pero lo probé y realmente no importó.
  • Todos los ejemplos darán la ruta completa a la carpeta. El ejemplo de pathlib como un objeto de ruta (Windows).
  • El primer elemento de os.walkserá la carpeta base. Por lo tanto, no obtendrá solo subdirectorios. Puedes usar fu.pop(0)para eliminarlo.
  • Ninguno de los resultados utilizará la clasificación natural . Esto significa que los resultados se ordenarán así: 1, 10, 2. Para obtener una clasificación natural (1, 2, 10), consulte https://stackoverflow.com/a/48030307/2441026


Resultados :

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

Probado 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()
usuario136036
fuente
35

Si necesita una solución recursiva que encuentre todos los subdirectorios en los subdirectorios, use walk como se propuso anteriormente.

Si solo necesita los directorios secundarios del directorio actual, combine os.listdirconos.path.isdir

Eli Bendersky
fuente
23

Implementado esto usando 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
fuente
19

Puede obtener la lista de subdirectorios (y archivos) en Python 2.7 usando os.listdir (ruta)

import os
os.listdir(path)  # list of subdirectories and files
Oscar Martin
fuente
59
Esto también incluye archivos.
Tarnay Kálmán
2
El nombre es confuso ya que 'dir' no se refiere a los objetos que forman la lista sino al directorio del contenedor. Verifique sus respuestas de una línea, para principiantes es muy tentador seleccionarlas.
Titou
44
Tenga cuidado con las os.listdirlistas de contenido del directorio, incluidos los archivos.
guneysus
13

Listado de directorios únicos

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)

Listado de solo archivos en el directorio actual

files = filter(os.path.isfile, os.listdir(os.curdir))
print("\nThe following are the list of all files in the current directory -")
print(files)
Tuerca
fuente
2
No funcionó en Mac OS. Creo que el problema es que os.listdir solo devuelve el nombre del directorio y no la ruta completa, pero os.path.isdir solo devuelve True si la ruta completa es un directorio.
denson
Esto funciona fuera del directorio actual si modifica ligeramente la línea: subdirs = filter (os.path.isdir, [os.path.join (dir, x) para x en os.listdir (dir)])
RLC
12

Python 3.4 introdujo el pathlibmódulo en la biblioteca estándar, que proporciona un enfoque orientado a objetos para manejar rutas del sistema de archivos:

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 también está disponible en Python 2.7 a través del módulo pathlib2 en PyPi.

joelostblom
fuente
Para iterar sobre la lista de subdirectorios, aquí hay una sintaxis agradable y limpia:for f in filter(Path.is_dir, p.iterdir()):
Bryan Roach
11

Como me topé con este problema usando las rutas Python 3.4 y Windows UNC, aquí hay una variante para este entorno:

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 es nuevo en Python 3.4 y hace que trabajar con rutas en diferentes sistemas operativos sea mucho más fácil: https://docs.python.org/3.4/library/pathlib.html

Marcus Schommler
fuente
10

Aunque esta pregunta fue respondida hace mucho tiempo. Quiero recomendar el uso del pathlibmódulo, ya que esta es una forma sólida de trabajar en Windows y Unix OS.

Entonces, para obtener todas las rutas en un directorio específico, incluidos los subdirectorios:

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
fuente
9

Gracias por los consejos chicos. Me encontré con un problema con los enlaces suaves (recursión infinita) que se devuelven como directorios. Softlinks? ¡No queremos enlaces apestosos! Entonces...

Esto representaba solo los directorios, no los enlaces suaves:

>>> import os
>>> inf = os.walk('.')
>>> [x[0] for x in inf]
['.', './iamadir']
KurtB
fuente
1
¿Qué se [x[0] for x in inf]llama en python para poder buscarlo?
shinzou
2
@shinzou Esa es una lista de comprensión. Super útil También busque comprensiones dictadas.
KurtB
9

Copiar y pegar amigable en ipython:

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

Salida de print(folders):

['folderA', 'folderB']
Andrew Schreiber
fuente
2
¿Qué es X en este caso?
Abhishek Parikh
1
@AbhishekParikh xes el elemento de la lista creada por os.listdir(d)porque listdirdevolverá los archivos y carpetas con los que está usando el filtercomando os.path.isdirpara filtrar los archivos de la lista.
James Burke,
8

Así es como lo hago.

    import os
    for x in os.listdir(os.getcwd()):
        if os.path.isdir(x):
            print(x)
Mujeeb Ishaque
fuente
No funciona. Supongo que en x tienes que proporcionar la ruta completa para verificar usando isdir ()
niranjan patidar
Probablemente tenga problemas con os.getcwd (); Esencialmente, lo que puede hacer es obtener el camino absoluto y usarlo en su lugar. dir = os.path.dirname (os.path.abspath ( archivo ))
Mujeeb Ishaque
usando os, pat.join () funcionó para mí. Porque ayudó a obtener la ruta completa del subdirectorio.
niranjan patidar
7

Aquí hay un par de funciones simples basadas en el ejemplo 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
fuente
6

Basándose en la solución de Eli Bendersky, use el siguiente ejemplo:

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"

¿Dónde <your_directory>está la ruta al directorio que desea recorrer?

Blairg23
fuente
5

Con la ruta completa y la contabilidad de ser camino ., .., \\, ..\\..\\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
fuente
4

Esta respuesta ya no parece existir.

directories = [ x for x in os.listdir('.') if os.path.isdir(x) ]
Andy
fuente
77
Esto siempre devolverá una lista vacía si está buscando algo que no sea el directorio de trabajo actual, que es técnicamente lo que el OP está buscando hacer, pero no es muy reutilizable.
ochawkeye
2
directorios = [x para x en os.listdir (localDir) if os.path.isdir (localDir + x)
Poonam
3

Recientemente tuve una pregunta similar y descubrí que la mejor respuesta para python 3.6 (como agregó el usuario havlock) es usarla os.scandir. Como parece que no hay solución para usarlo, agregaré la mía. Primero, una solución no recursiva que enumera solo los subdirectorios directamente bajo el directorio raíz.

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 versión recursiva se vería así:

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

tenga en cuenta que entry.pathmaneja la ruta absoluta al subdirectorio. En caso de que solo necesite el nombre de la carpeta, puede usar entry.nameen su lugar. Consulte os.DirEntry para obtener detalles adicionales sobre el entryobjeto.

Alberto A
fuente
En realidad, la forma en que está escrito no funcionará en 3.5, solo 3.6. Para usar en 3.5, debe eliminar el administrador de contexto: consulte stackoverflow.com/questions/41401417/…
havlock el
Esto es correcto. Podría jurar que leí en alguna parte que el administrador de contexto se implementó en 3.5, pero parece que estoy equivocado.
Alberto A
1

usar una función de filtro os.path.isdirsobre os.listdir() algo como estofilter(os.path.isdir,[os.path.join(os.path.abspath('PATH'),p) for p in os.listdir('PATH/')])

onePeggedChicken
fuente
1

Esto mostrará una lista de todos los subdirectorios en el árbol de archivos.

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 es nuevo en la versión 3.4

Yossarian42
fuente
1

Función para devolver una lista de todos los subdirectorios dentro de una ruta de archivo determinada. Buscará en todo el árbol de archivos.

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
fuente
1

podemos obtener una lista de todas las carpetas usando os.walk ()

import os

path = os.getcwd()

pathObject = os.walk(path)

este pathObject es un objeto y podemos obtener una matriz por

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

Podemos obtener una lista de todos los subdirectorios iterando a través del arr e imprimiendo la matriz del medio

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

Esto imprimirá todo el subdirectorio.

Para obtener todos los archivos:

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

Esta función, con un padre dado, directoryitera sobre todo su directoriesrecursividad y printstodo filenameslo que encuentra dentro. Demasiado útil

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
fuente
0

Al unir varias soluciones desde aquí, esto es lo que terminé usando:

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, '*')))]
TristeSiete
fuente