Obtendo uma lista de todos os subdiretórios no diretório atual

Respostas:

604

Você quer dizer subdiretórios imediatos ou todos os diretórios da árvore?

De qualquer forma, você pode usar os.walkpara fazer isso:

os.walk(directory)

produzirá uma tupla para cada subdiretório. A primeira entrada na 3-tupla é um nome de diretório, portanto

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

deve fornecer todos os subdiretórios, recursivamente.

Observe que a segunda entrada na tupla é a lista de diretórios filhos da entrada na primeira posição; portanto, você pode usá-la, mas provavelmente não economizará muito.

No entanto, você pode usá-lo apenas para fornecer os diretórios filhos imediatos:

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

Ou veja as outras soluções já postadas, usando os.listdire os.path.isdir, incluindo aquelas em " Como obter todos os subdiretórios imediatos no Python ".

Blair Conrad
fonte
7
Eu acho que os.walk retorna triplos (root, dirs, arquivos). O que significa que dirs tem muitas entradas repetidas. Existe uma maneira mais eficiente de se repetir nos diretórios?
mathtick
22
Não use os.walk('.').next()[1]ou os.walk('.').__next__()[1]diretamente. Em vez disso, use a função interna next(), disponível no Python 2 (consulte o documento) e Python 3 (consulte o documento) . Por exemplo: next(os.walk('.'))[1].
Lucio Paiva
1
@ Lucio Por que é ruim usar os.walk('.').next()[1]diretamente?
wisbucky
8
@wisbucky é uma prática ruim, porque iteraror.__next__()é um método interno e o iterator.next()uso deve ser transferido para o interno de next()acordo com o PEP-3114. Veja PEP-3114 que foi aprovado em 2007.
Lucio Paiva
16
Para qualquer pessoa preocupada com as diferenças de desempenho entre as soluções + os.walke : Acabei de testar em um diretório com 10.000 subdiretórios (com milhões de arquivos na hierarquia abaixo) e as diferenças de desempenho são desprezíveis. : "10 loops, o melhor de 3: 44,6 mseg por loop" e + : "10 loops, o melhor de 3: 45,1 mseg por loop"os.listdiros.path.isdiros.walkos.listdiros.path.isdir
kevinmicke 28/02/17
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
fonte
5
observe que nessa abordagem você precisa cuidar dos problemas do abspath se não for executado em '.'
Daspostloch 29/05
4
Apenas um heads-up, se você não estiver usando o cwd ( ''), isso não vai funcionar a menos que você faça uma os.path.joinem oobter o caminho completo, caso contrário, isdir(0)sempre retornará false
James McMahon
5
Parece que a postagem foi atualizada com correções para os dois problemas mencionados acima.
Cgmb
1
Para evitar ligar os.path.joinduas vezes, primeiro você pode ingressar e filtrar a lista usando os.path.isdir: filter(os.path.isdir, [os.path.join(d, o) for o in os.listdir(d)])
quant_dev 14/06/19
155

Você poderia apenas usar glob.glob

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

Não esqueça o rastro /após o *.

Udit Bansal
fonte
Agradável. Simples. Somente, deixa o /
rasto
9
Se você não pode assumir /que é o separador de pastas, faça o seguinte:glob(os.path.join(path_to_directory, "*", ""))
juanmirocks 21/03
1
Isso não funciona para subdiretórios! Para usar glob, aqui está a resposta completa: Use um Glob () para encontrar arquivos recursivamente em Python?
Poppie
1
para fazer glob recursiva você pode apenas adicionar o seguinte argumentorecursive=True
JacoSolari
102

Muito melhor do que o acima, porque você não precisa de vários os.path.join () e obterá o caminho completo diretamente (se desejar), você pode fazer isso no Python 3.5 e acima.

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

Isso fornecerá o caminho completo para o subdiretório. Se você deseja apenas o nome do subdiretório, use em f.namevez def.path

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


Ligeiramente OT: Caso você precise de todas as subpastas recursivamente e / ou todos os arquivos recursivamente , observe esta função, que é mais rápida que os.walk& globe retornará uma lista de todas as subpastas, bem como de todos os arquivos dentro dessas (sub) subpastas: https://stackoverflow.com/a/59803793/2441026

Caso você queira apenas todas as subpastas recursivamente :

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

Retorna uma lista de todas as subpastas com seus caminhos completos. Isso novamente é mais rápido que os.walke muito mais rápido que glob.


Uma análise de todas as funções

tl; dr:
- Se você deseja obter todos os subdiretórios imediatos para uma pasta, use os.scandir.
- Se você deseja obter todos os subdiretórios, mesmo os aninhados , use os.walkou - um pouco mais rápido - a fast_scandirfunção acima.
- Nunca use os.walkapenas subdiretórios de nível superior, pois pode ser centenas (!) De vezes mais lento que os.scandir.

  • Se você executar o código abaixo, execute-o uma vez para que o sistema operacional acesse a pasta, descarte os resultados e execute o teste, caso contrário, os resultados serão danificados.
  • Você pode querer misturar as chamadas de função, mas eu testei, e isso realmente não importava.
  • Todos os exemplos fornecerão o caminho completo para a pasta. O exemplo pathlib como um objeto Path (Windows).
  • O primeiro elemento de os.walkserá a pasta base. Portanto, você não receberá apenas subdiretórios. Você pode usar fu.pop(0)para removê-lo.
  • Nenhum dos resultados usará classificação natural . Isso significa que os resultados serão classificados da seguinte forma: 1, 10, 2. Para obter a classificação 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

Testado com 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
fonte
35

Se você precisar de uma solução recursiva que encontre todos os subdiretórios nos subdiretórios, use walk como proposto anteriormente.

Se você precisar apenas dos diretórios filhos do diretório atual, combine os.listdircomos.path.isdir

Eli Bendersky
fonte
23

Implementado isso 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
fonte
19

Você pode obter a lista de subdiretórios (e arquivos) no Python 2.7 usando os.listdir (caminho)

import os
os.listdir(path)  # list of subdirectories and files
Oscar Martin
fonte
59
Isso inclui arquivos também.
Tarnay Kálmán 14/10
2
O nome é confuso, pois 'dir' não se refere aos objetos que formam a lista, mas ao diretório do contêiner. Por favor, verifique suas respostas em uma linha, para iniciantes é muito tentador selecioná-las.
Titou
4
Cuidado com isso os.listdirlista o conteúdo do diretório, incluindo arquivos.
26616 guneysus
13

Listando apenas diretórios

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)

Listando apenas arquivos no diretório atual

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
fonte
2
Não funcionou no mac OS. Eu acho que o problema é que os.listdir retorna apenas o nome do diretório e não o caminho completo, mas os.path.isdir retorna apenas True se o caminho completo for um diretório.
denson
Isso funciona fora do diretório atual se você modificar ligeiramente a linha: subdirs = filter (os.path.isdir, [os.path.join (dir, x) para x em os.listdir (dir)])
RLC
12

O Python 3.4 introduziu o pathlibmódulo na biblioteca padrão, que fornece uma abordagem orientada a objetos para lidar com os caminhos do sistema de arquivos:

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('**/'))

O Pathlib também está disponível no Python 2.7 através do módulo pathlib2 no PyPi.

joelostblom
fonte
Para percorrer a lista de subdiretórios, aqui está uma sintaxe agradável e limpa:for f in filter(Path.is_dir, p.iterdir()):
Bryan Roach
11

Desde que me deparei com esse problema usando caminhos Python 3.4 e Windows UNC, aqui está uma variante para esse 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)

O Pathlib é novo no Python 3.4 e facilita muito o trabalho com caminhos em diferentes sistemas operacionais: https://docs.python.org/3.4/library/pathlib.html

Marcus Schommler
fonte
10

Embora esta pergunta seja respondida há muito tempo. Quero recomendar o uso do pathlibmódulo, pois essa é uma maneira robusta de trabalhar no Windows e no Unix OS.

Portanto, para obter todos os caminhos em um diretório específico, incluindo subdiretórios:

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

Obrigado pelas dicas, pessoal. Corri um problema com softlinks (recursão infinita) sendo retornados como dirs. Softlinks? Não queremos links fedorentos! Assim...

Isso renderizou apenas os diretórios, não os softlinks:

>>> import os
>>> inf = os.walk('.')
>>> [x[0] for x in inf]
['.', './iamadir']
KurtB
fonte
1
O que é [x[0] for x in inf]chamado em python para que eu possa procurar?
Shinzou
2
@shinzou Essa é uma lista de compreensão. Super útil. Procure também compreensões de ditado.
22418 KurtB
9

Copiar e colar amigável em ipython:

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

Saída de print(folders):

['folderA', 'folderB']
Andrew Schreiber
fonte
2
O que é X neste caso?
Abhishek Parikh 28/10
1
@AbhishekParikh xé o item da lista criada por, os.listdir(d)pois listdirretornará arquivos e pastas com os quais ele está usando o filtercomando os.path.isdirpara filtrar todos os arquivos da lista.
James Burke
8

É assim que eu faço.

    import os
    for x in os.listdir(os.getcwd()):
        if os.path.isdir(x):
            print(x)
Mujeeb Ishaque
fonte
Isso não funciona. Eu acho que em x você tem que fornecer o caminho completo para verificar usando isdir ()
niranjan patidar
Você provavelmente está tendo problemas com os.getcwd (); Essencialmente, o que você pode fazer é obter o caminho absoluto e usá-lo. dir = os.path.dirname (os.path.abspath ( arquivo ))
Mujeeb Ishaque 20/03
usando os, pat.join () funcionou para mim. Porque ajudou a obter o caminho completo do subdiretório.
niranjan patidar 25/03
7

Aqui estão algumas funções simples baseadas no exemplo 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
fonte
6

Com base na solução de Eli Bendersky, use o seguinte exemplo:

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"

Onde <your_directory>está o caminho para o diretório que você deseja percorrer.

Blairg23
fonte
5

Com caminho completo e contabilidade para estar caminho ., .., \\, ..\\..\\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
fonte
4

Essa resposta parecia não existir já.

directories = [ x for x in os.listdir('.') if os.path.isdir(x) ]
Andy
fonte
7
Isso sempre retornará uma lista vazia se você estiver pesquisando algo diferente do diretório de trabalho atual, que é tecnicamente o que o OP está procurando fazer, mas não é muito reutilizável.
Ochawkeye
2
directórios = [x para x em os.listdir (localdir) se os.path.isdir (localdir + x)
Poonam
3

Recentemente, tive uma pergunta semelhante e descobri que a melhor resposta para o python 3.6 (conforme adicionado pelo usuário) é usar os.scandir. Como parece que não há solução para usá-lo, vou adicionar o meu. Primeiro, uma solução não recursiva que lista apenas os subdiretórios diretamente no diretório raiz.

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

A versão recursiva ficaria assim:

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

tenha em mente que entry.pathexerce o caminho absoluto para o subdiretório. Caso você precise apenas do nome da pasta, você pode usá-lo entry.name. Consulte os.DirEntry para obter detalhes adicionais sobre o entryobjeto.

Alberto A
fonte
Na verdade, da maneira como está escrito, não funcionará no 3.5, apenas 3.6. Para usar em 3,5 você precisa remover gerente de contexto - veja stackoverflow.com/questions/41401417/...
havlock
Isto está correto. Eu poderia jurar que li em algum lugar que o gerenciador de contexto foi implementado na 3.5, mas parece que estou errado.
Alberto A
1

use uma função de filtro os.path.isdirsobre os.listdir() algo como istofilter(os.path.isdir,[os.path.join(os.path.abspath('PATH'),p) for p in os.listdir('PATH/')])

oneLeggedChicken
fonte
1

Isso listará todos os subdiretórios na árvore de arquivos.

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 é novo na versão 3.4

Yossarian42
fonte
1

Função para retornar uma Lista de todos os subdiretórios dentro de um determinado caminho do arquivo. Irá pesquisar em toda a árvore de arquivos.

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

podemos obter uma lista de todas as pastas usando os.walk ()

import os

path = os.getcwd()

pathObject = os.walk(path)

esse pathObject é um objeto e podemos obter uma matriz

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 obter a lista de todos os subdiretórios iterando através da arr e imprimindo a matriz intermediária

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

Isso imprimirá todo o subdiretório.

Para obter todos os arquivos:

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

Essa função, com um determinado pai, directoryrepete toda a sua directoriesrecursividade e printstudo o filenamesque encontra por dentro. Muito ú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
fonte
0

Juntando várias soluções a partir daqui, foi isso que acabei 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, '*')))]
SadSeven
fonte