Uzyskiwanie listy wszystkich podkatalogów w bieżącym katalogu

Odpowiedzi:

602

Masz na myśli bezpośrednie podkatalogi, czy każdy katalog bezpośrednio w drzewie?

Tak czy inaczej, możesz to os.walkzrobić:

os.walk(directory)

da krotkę dla każdego podkatalogu. Pierwszym wpisem w 3-krotce jest nazwa katalogu, więc

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

powinien rekurencyjnie dać ci wszystkie podkatalogi.

Zauważ, że drugi wpis w krotce to lista katalogów potomnych wpisu na pierwszej pozycji, więc możesz użyć tego zamiast tego, ale raczej nie zaoszczędzisz dużo.

Jednak możesz go użyć tylko po to, aby dać ci bezpośrednie katalogi potomne:

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

Lub zobacz inne opublikowane już rozwiązania, wykorzystujące os.listdiri os.path.isdir, w tym te z „ Jak uzyskać wszystkie bezpośrednie podkatalogi w Pythonie ”.

Blair Conrad
źródło
7
Myślę, że os.walk zwraca tróje (root, katalogi, pliki). Co oznacza, że ​​katalog zawiera wiele powtarzających się wpisów. Czy istnieje bardziej skuteczny sposób, który powtarza się w katalogach?
mathtick,
22
Nie używaj os.walk('.').next()[1]ani os.walk('.').__next__()[1]bezpośrednio. Zamiast tego użyj wbudowanej funkcji next(), która jest dostępna zarówno w Pythonie 2 (patrz dokument), jak i Python 3 (patrz dokument) . Na przykład: next(os.walk('.'))[1].
Lucio Paiva,
1
@Lucio Dlaczego warto używać os.walk('.').next()[1]bezpośrednio?
wisbucky,
8
@wisbucky to zła praktyka, ponieważ iteraror.__next__()jest to metoda wewnętrzna, a iterator.next()użycie należy przenieść do wbudowanego next()zgodnie z PEP-3114. Zobacz PEP-3114, który został zatwierdzony w 2007 r.
Lucio Paiva,
16
Dla zainteresowanych o różnice w wynikach pomiędzy nikogo os.walki os.listdir+ os.path.isdirrozwiązań: Właśnie testowany na katalogu z 10.000 podkatalogów (z milionów plików w hierarchii poniżej), a różnice w wynikach są znikome. os.walk: „10 pętli, najlepiej 3: 44,6 ms na pętlę” i os.listdir+ os.path.isdir: „10 pętli, najlepiej 3: 45,1 ms na pętlę”
kevinmicke
166
import os

d = '.'
[os.path.join(d, o) for o in os.listdir(d) 
                    if os.path.isdir(os.path.join(d,o))]
gahooa
źródło
5
zwróć uwagę, że w tym podejściu musisz dbać o problemy z abspath, jeśli nie zostanie wykonane na „.”
daspostloch
4
Zaledwie heads-up, jeśli nie używasz CWD ( „”), to nie będzie działać, chyba że zrobić os.path.joinna ouzyskać pełną ścieżkę, inaczej isdir(0)będzie zawsze return false
James McMahon
5
Wygląda na to, że post został zaktualizowany o poprawki dwóch wyżej wymienionych problemów.
cgmb,
1
Aby uniknąć os.path.joinpodwójnego dzwonienia , możesz najpierw dołączyć, a następnie przefiltrować listę, używając os.path.isdir: filter(os.path.isdir, [os.path.join(d, o) for o in os.listdir(d)])
quant_dev
154

Możesz po prostu użyć glob.glob

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

Nie zapomnij o zakończeniu /po *.

Udit Bansal
źródło
Miły. Prosty. Tylko pozostawia ślad /w nazwach
juanmirocks
9
Jeśli nie możesz założyć, /że to separator folderów, zrób to:glob(os.path.join(path_to_directory, "*", ""))
juanmirocks
1
To nie działa w przypadku podkatalogów! Aby użyć glob, oto pełna odpowiedź: Użyj Glob (), aby znaleźć pliki rekurencyjnie w Pythonie?
poppie
1
aby glob był rekurencyjny, wystarczy dodać następujący argumentrecursive=True
JacoSolari,
102

O wiele ładniejsze niż powyższe, ponieważ nie potrzebujesz kilku os.path.join () i otrzymasz pełną ścieżkę bezpośrednio (jeśli chcesz), możesz to zrobić w Pythonie 3.5 i nowszych.

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

To da pełną ścieżkę do podkatalogu. Jeśli chcesz tylko użyć nazwy podkatalogu f.namezamiastf.path

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


Nieznacznie OT: Jeśli potrzebujesz rekursywnie wszystkich podfolderów i / lub wszystkich plików , spójrz na tę funkcję, która jest szybsza niż os.walk& globi zwróci listę wszystkich podfolderów, a także wszystkich plików w tych (pod-) podfolderach: https://stackoverflow.com/a/59803793/2441026

Jeśli chcesz rekurencyjnie tylko wszystkich podfolderów :

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

Zwraca listę wszystkich podfolderów wraz z ich pełnymi ścieżkami. To znowu jest szybsze os.walki dużo szybsze niż glob.


Analiza wszystkich funkcji

tl; dr:
- Jeśli chcesz uzyskać wszystkie bezpośrednie podkatalogi do wykorzystania w folderze os.scandir.
- Jeśli chcesz uzyskać wszystkie podkatalogi, nawet zagnieżdżone , użyj os.walklub - nieco szybciej - fast_scandirpowyższej funkcji.
- Nigdy nie używaj os.walktylko podkatalogów najwyższego poziomu, ponieważ mogą być setki (!) Razy wolniejsze niż os.scandir.

  • Jeśli uruchomisz poniższy kod, pamiętaj, aby uruchomić go raz, aby system operacyjny uzyskał dostęp do folderu, odrzuć wyniki i uruchom test, w przeciwnym razie wyniki zostaną skręcone.
  • Być może chcesz pomieszać wywołania funkcji, ale przetestowałem to i nie miało to większego znaczenia.
  • Wszystkie przykłady podadzą pełną ścieżkę do folderu. Przykład pathlib jako obiekt ścieżki (Windows).
  • Pierwszym elementem os.walkbędzie folder podstawowy. Więc nie dostaniesz tylko podkatalogów. Możesz go użyć fu.pop(0)do usunięcia.
  • Żaden z wyników nie będzie korzystał z naturalnego sortowania . Oznacza to, że wyniki zostaną posortowane w następujący sposób: 1, 10, 2. Aby uzyskać naturalne sortowanie (1, 2, 10), zajrzyj na https://stackoverflow.com/a/48030307/2441026


Wyniki :

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

Testowane z 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()
użytkownik136036
źródło
35

Jeśli potrzebujesz rozwiązania rekurencyjnego, które znajdzie wszystkie podkatalogi w podkatalogach, skorzystaj z marszu zgodnie z wcześniejszą propozycją.

Jeśli potrzebujesz tylko katalogów potomnych bieżącego katalogu, połącz os.listdirzos.path.isdir

Eli Bendersky
źródło
23

Zaimplementowano to za pomocą 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
źródło
19

Możesz uzyskać listę podkatalogów (i plików) w Pythonie 2.7, używając os.listdir (ścieżka)

import os
os.listdir(path)  # list of subdirectories and files
Oscar Martin
źródło
59
Dotyczy to również plików.
Tarnay Kálmán
2
Nazwa jest myląca, ponieważ „katalog” nie odnosi się do obiektów tworzących listę, ale do katalogu kontenera. Sprawdź swoje odpowiedzi w jednej linii, dla początkujących bardzo kuszące jest ich wybranie.
Titou
4
Uwaga: os.listdirzawiera listę zawartości katalogu, w tym plików.
guneysus
13

Wyświetlanie tylko katalogów

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)

Wyświetlanie tylko plików w bieżącym katalogu

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
źródło
2
Nie działał w systemie Mac OS. Myślę, że problem polega na tym, że os.listdir zwraca tylko nazwę katalogu, a nie pełną ścieżkę, ale os.path.isdir zwraca True tylko wtedy, gdy pełna ścieżka jest katalogiem.
denson
Działa to poza bieżącym katalogiem, jeśli nieznacznie zmodyfikujesz wiersz: subdirs = filter (os.path.isdir, [os.path.join (dir, x) for x in os.listdir (dir)])
RLC
12

Python 3.4 wprowadziła ten pathlibmoduł do standardowej biblioteki, która zapewnia podejścia obiektowego do ścieżek uchwyt systemu plików:

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 jest również dostępny w Pythonie 2.7 za pośrednictwem modułu pathlib2 w PyPi.

joelostblom
źródło
Aby przejrzeć listę podkatalogów, oto ładna, czysta składnia:for f in filter(Path.is_dir, p.iterdir()):
Bryan Roach
11

Ponieważ natknąłem się na ten problem przy użyciu ścieżek Python 3.4 i Windows UNC, oto wariant tego środowiska:

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 jest nowością w Pythonie 3.4 i znacznie ułatwia pracę ze ścieżkami w różnych systemach operacyjnych: https://docs.python.org/3.4/library/pathlib.html

Marcus Schommler
źródło
10

Chociaż na to pytanie dawno już udzielono odpowiedzi. Chcę polecić korzystanie zpathlib modułu, ponieważ jest to niezawodny sposób pracy w systemach operacyjnych Windows i Unix.

Aby uzyskać wszystkie ścieżki w określonym katalogu, w tym w podkatalogach:

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

itp.

Joost Döbken
źródło
9

Dzięki za wskazówki, chłopaki. Wystąpił problem polegający na tym, że softlinks (nieskończona rekurencja) był zwracany jako reż. Softlinks? Nie chcemy żadnych śmierdzących miękkich linków! Więc...

To renderowało tylko katalogi, a nie linki miękkie:

>>> import os
>>> inf = os.walk('.')
>>> [x[0] for x in inf]
['.', './iamadir']
KurtB
źródło
1
Jak [x[0] for x in inf]nazywa się Python, abym mógł to sprawdzić?
shinzou
2
@shinzou To zrozumienie listy. Super przydatne. Poszukaj także rozumienia dykt.
KurtB
9

Kopiuj wklej przyjazny w ipython:

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

Wyjście z print(folders):

['folderA', 'folderB']
Andrew Schreiber
źródło
2
Co to jest X w tym przypadku?
Abhishek Parikh
1
@AbhishekParikh xjest pozycją z listy utworzonej przez, os.listdir(d)ponieważ listdirzwróci pliki i foldery, których używa filterpolecenia, os.path.isdiraby odfiltrować dowolne pliki z listy.
James Burke
8

Tak to robię.

    import os
    for x in os.listdir(os.getcwd()):
        if os.path.isdir(x):
            print(x)
Mujeeb Ishaque
źródło
To nie działa. Chyba w x musisz podać pełną ścieżkę do sprawdzenia za pomocą isdir ()
niranjan patidar
Prawdopodobnie masz problem z os.getcwd (); Zasadniczo możesz uzyskać ścieżkę bezwzględną i użyć jej zamiast tego. katalog = os.path.dirname (os.path.abspath ( plik ))
Mujeeb Ishaque
using os, pat.join () działało dla mnie. Ponieważ pomogło to uzyskać pełną ścieżkę do podkatalogu.
niranjan patidar
7

Oto kilka prostych funkcji opartych na przykładzie @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
źródło
6

Opierając się na rozwiązaniu Eli Benderskiego, skorzystaj z następującego przykładu:

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"

gdzie <your_directory>jest ścieżka do katalogu, który chcesz przejść.

Blairg23
źródło
5

Z pełną ścieżką i rozliczania ścieżki samopoczucia ., .., \\, ..\\..\\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
źródło
4

Ta odpowiedź chyba jeszcze nie istniała.

directories = [ x for x in os.listdir('.') if os.path.isdir(x) ]
Andy
źródło
7
To zawsze zwróci pustą listę, jeśli szukasz czegoś innego niż bieżący katalog roboczy, co jest technicznie tym, czego OP chce zrobić, ale niezbyt wielokrotnego użytku.
ochawkeye
2
katalogi = [x dla x w os.listdir (localDir) if os.path.isdir (localDir + x)
Poonam
3

Ostatnio miałem podobne pytanie i dowiedziałem się, że najlepszą odpowiedzią na python 3.6 (jak dodał użytkownik havlock) jest użycie os.scandir. Ponieważ wydaje się, że nie ma rozwiązania, które go wykorzysta, dodam własne. Po pierwsze, nierekurencyjne rozwiązanie, które wyświetla tylko podkatalogi bezpośrednio w katalogu głównym.

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

Wersja rekurencyjna wyglądałaby tak:

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

pamiętaj, że prowadzi entry.pathabsolutną ścieżkę do podkatalogu. Jeśli potrzebujesz tylko nazwy folderu, możesz użyć entry.namezamiast tego. Dodatkowe informacje na temat obiektu można znaleźć w os.DirEntryentry .

Alberto A.
źródło
W rzeczywistości sposób, w jaki jest napisany, nie będzie działał na 3.5, tylko 3.6. Aby korzystać z wersji 3.5, musisz usunąć menedżera kontekstu - patrz stackoverflow.com/questions/41401417/…
havlock
To jest poprawne. Mógłbym przysiąc, że gdzieś przeczytałem, że menedżer kontekstu został zaimplementowany w wersji 3.5, ale wygląda na to, że się mylę.
Alberto,
1

użyj funkcji filtrowania os.path.isdirnad os.listdir() czymś takimfilter(os.path.isdir,[os.path.join(os.path.abspath('PATH'),p) for p in os.listdir('PATH/')])

oneLeggedChicken
źródło
1

Spowoduje to wyświetlenie wszystkich podkatalogów bezpośrednio w drzewie plików.

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 jest nowy w wersji 3.4

Yossarian42
źródło
1

Funkcja zwracająca listę wszystkich podkatalogów w ramach danej ścieżki pliku. Przeszukuje całe drzewo plików.

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
źródło
1

możemy uzyskać listę wszystkich folderów za pomocą os.walk ()

import os

path = os.getcwd()

pathObject = os.walk(path)

ten pathObject jest obiektem i możemy uzyskać tablicę według

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

Możemy uzyskać listę wszystkich podkatalogów, iterując przez arr i wypisując środkową tablicę

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

Spowoduje to wydrukowanie całego podkatalogu.

Aby uzyskać wszystkie pliki:

for i in arr:
   for j in i[2]:
      print(i[0] + "/" + j)
Shivam Kesarwani
źródło
0

Ta funkcja, z danym rodzicem, directoryiteruje wszystkie directoriesrekurencyjnie i printswszystko, filenamesco znajduje w sobie. Zbyt przydatne

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
źródło
0

Przyłączając się do wielu rozwiązań stąd, wykorzystałem to:

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
źródło