Отримання списку всіх підкаталогів у поточному каталозі


558

Чи є спосіб повернути список усіх підкаталогів у поточному каталозі в Python?

Я знаю, що ви можете це зробити з файлами, але мені потрібно отримати список каталогів.


Відповіді:


602

Ви маєте на увазі безпосередні підкаталоги або кожен каталог прямо вниз по дереву?

У будь-якому випадку ви можете скористатися os.walkдля цього:

os.walk(directory)

дасть кортеж для кожного підкаталогу. Першим записом у 3-кортежі є ім'я каталогу, так

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

має надавати вам усі підкаталоги, рекурсивно.

Зауважте, що другий запис у кортежі - це список дочірніх каталогів цього запису на першій позиції, тож ви можете використовувати це замість цього, але це, ймовірно, значно не заощадить.

Однак ви можете використовувати його просто для того, щоб отримати безпосередні довідники:

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

Або подивіться інші опубліковані рішення, використовуючи os.listdirта os.path.isdir, в тому числі в розділі " Як отримати всі безпосередні підкаталоги в Python ".


7
Я думаю, що os.walk повертає трійки (root, dirs, файли). Що означає, що у dirs є багато повторюваних записів. Чи є більш ефективний спосіб, який повторюється через каталоги?
mathtick

22
Не використовуйте os.walk('.').next()[1]або os.walk('.').__next__()[1]безпосередньо. Натомість використовуйте вбудовану функцію next(), яка доступна як у Python 2 (див. Doc), так і в Python 3 (див. Doc) . Наприклад: next(os.walk('.'))[1].
Лусіо Паїва

1
@Lucio Чому погано використовувати os.walk('.').next()[1]безпосередньо?
вісбукі

8
@wisbucky - це погана практика, оскільки iteraror.__next__()це внутрішній метод, і iterator.next()використання має бути переведене на вбудований next()відповідно до PEP-3114. Дивіться PEP-3114, який був затверджений у 2007 році.
Лусіо Пайва

16
Для всіх, хто стурбований розбіжностями між рішеннями os.walkта os.listdir+ os.path.isdirрішеннями: я щойно перевірив каталог із 10000 підкаталогами (з мільйонами файлів в ієрархії нижче), і відмінності в продуктивності незначні. os.walk: "10 петель, найкраще 3: 44,6 мс на цикл" і os.listdir+ os.path.isdir: "10 петель, найкраще 3: 45,1 мсек за петлю"
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
зауважте, що при такому підході вам потрібно піклуватися про abspath-проблеми, якщо вони не виконуються "."
daspostloch

4
Всього голови вгору, якщо ви не використовуєте ВУХО ( «»), то це не буде працювати , якщо ви не зробите os.path.joinна , oщоб отримати повний шлях, в іншому випадку isdir(0)завжди буде повертати брехня
Джеймс МакМахон

5
Здається, публікація була оновлена ​​з виправленнями для двох вищезгаданих проблем.
cgmb

1
Щоб уникнути дзвінків os.path.joinдвічі, спершу ви можете приєднатись, а потім відфільтрувати список, використовуючи os.path.isdir: filter(os.path.isdir, [os.path.join(d, o) for o in os.listdir(d)])
quant_dev

155

Ви могли просто використовувати glob.glob

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

Не забувайте про слідування /після *.


Приємно. Простий. Тільки він залишає слід /у назвах
juanmirocks

9
Якщо ви не можете вважати себе /роздільником папок, зробіть це:glob(os.path.join(path_to_directory, "*", ""))
juanmirocks

1
Це не працює для підкаталогів! Щоб використовувати глобус, ось повний відповідь: Використовуйте Glob (), щоб знайти файли рекурсивно в Python?
мак

1
щоб зробити глобальний рекурсивний, ви можете просто додати наступний аргументrecursive=True
JacoSolari

102

Набагато приємніше, ніж вище, тому що вам не потрібно кілька os.path.join (), і ви отримаєте повний шлях безпосередньо (якщо хочете), ви можете зробити це в Python 3.5 і вище.

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

Це дасть повний шлях до підкаталогу. Якщо ви хочете використовувати лише ім'я підкаталогу, f.nameа не використовуватиf.path

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


Трохи OT: Якщо вам потрібні всі підпапки рекурсивно та / або всі файли рекурсивно , перегляньте цю функцію, яка швидше, ніж os.walk&, globі поверне список усіх підпапок, а також усіх файлів у цих підпапках: https://stackoverflow.com/a/59803793/2441026

Якщо ви хочете, щоб усі підпапки були рекурсивно :

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

Повертає список усіх підпапок з їх повними шляхами. Це знову швидше os.walkі набагато швидше, ніж glob.


Аналіз усіх функцій

tl; dr:
- Якщо ви хочете отримати всі негайні підкаталоги для використання папки os.scandir.
- Якщо ви хочете отримати всі підкаталоги, навіть вкладені , скористайтесь функцією os.walkабо - трохи швидше - fast_scandirвище.
- Ніколи не використовуйте os.walkлише підкаталоги верхнього рівня, оскільки це може бути в сотні (!) Разів повільніше, ніж os.scandir.

  • Якщо ви запустили код нижче, переконайтеся, що запустити його один раз, щоб ваша ОС отримала доступ до папки, відкиньте результати та запустіть тест, інакше результати будуть накручені.
  • Можливо, ви захочете змішати виклики функцій, але я перевірив її, і це насправді не мало значення.
  • Усі приклади дадуть повний шлях до папки. Приклад шляху в якості об'єкта Path (Windows).
  • Першим елементом os.walkбуде основна папка. Так ви не отримаєте лише підкаталоги. Ви можете використовувати його fu.pop(0)для видалення.
  • Жоден з результатів не використовує природне сортування . Це означає, що результати будуть сортовані так: 1, 10, 2. Щоб отримати природне сортування (1, 2, 10), перегляньте https://stackoverflow.com/a/48030307/2441026


Результати :

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

Тестовано на 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

Якщо вам потрібне рекурсивне рішення, яке знайде всі підкаталоги у підкаталогах, використовуйте ходьбу, як було запропоновано раніше.

Якщо вам потрібні лише дочірні каталоги поточного каталогу, комбінуйте os.listdirзos.path.isdir




19

Ви можете отримати список підкаталогів (і файлів) в Python 2.7, використовуючи os.listdir (шлях)

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

59
Сюди також входять файли.
Тарнай Калман

2
Назва є заплутаною, оскільки "dir" не стосується об'єктів, що формують список, а до каталогу контейнерів. Будь ласка, перевірте свої однорядкові відповіді, для початківців дуже спокусливо їх вибрати.
Тіту

4
Остерігайтеся цього, os.listdirперераховується вміст каталогу, включаючи файли.
guneysus

13

Лістинг лише каталогів

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)

Перелік лише файлів у поточному каталозі

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
Не працював на Mac OS. Я думаю, що проблема полягає в тому, що os.listdir повертає лише ім'я каталогу, а не повний шлях, але os.path.isdir повертає True, лише якщо повний шлях є каталогом.
денсон

Це працює за межами поточного каталогу, якщо ви трохи змінили рядок: subdirs = filter (os.path.isdir, [os.path.join (dir, x) for x in os.listdir (dir)])
RLC

12

Python 3.4 вводиться в pathlibмодулі в стандартну бібліотеку, яка забезпечує об'єктно - орієнтований підхід для обробки файлової системи шляхів:

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 також доступний на Python 2.7 через модуль pathlib2 на PyPi.


Щоб повторити список підкаталогів, ось приємний чистий синтаксис:for f in filter(Path.is_dir, p.iterdir()):
Брайан Роуч

11

Оскільки я натрапив на цю проблему, використовуючи шляхи Python 3.4 та Windows UNC, ось такий варіант для цього середовища:

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 є новим у Python 3.4 і значно спрощує роботу з шляхами під різними ОС: https://docs.python.org/3.4/library/pathlib.html


10

Хоча на це запитання відповіли давно. Я хочу порекомендувати використовуватиpathlib модуль, оскільки це надійний спосіб роботи в ОС Windows і Unix.

Отже, щоб отримати всі шляхи до певного каталогу, включаючи підкаталоги:

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

тощо.


9

Дякую за поради, хлопці. Я зіткнувся з проблемою, коли softlinks (нескінченна рекурсія) повертався як dirs. Софтпосилання? Ми не хочемо ніяких смердючих м'яких посилань! Тому...

Це виводило просто бруди, а не софтпосилання:

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

1
Що [x[0] for x in inf]називається python, щоб я міг його переглянути?
shinzou

2
@shinzou Ось розуміння списку. Супер корисно. Подивіться також на розуміння дикту.
КуртБ

9

Скопіюйте дружню пасту на ipython:

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

Вихід від print(folders):

['folderA', 'folderB']

2
Що таке X у цьому випадку?
Абхішек Парих

1
@AbhishekParikh x- це пункт зі списку, створений, os.listdir(d)тому що listdirповерне файли та папки, з якими він використовує filterкоманду os.path.isdirдля фільтрації будь-яких файлів зі списку.
Джеймс Берк

8

Ось як я це роблю.

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

Це не працює. Я думаю, у x ви повинні надати повний шлях для перевірки за допомогою isdir ()
niranjan patidar

Напевно у вас проблеми з os.getcwd (); По суті, ви можете зробити абсолютний шлях і скористатися цим. dir = os.path.dirname (os.path.abspath ( файл ))
Mujeeb Ishaque

використовуючи os, pat.join () працював на мене. Тому що це допомогло отримати повний шлях до підкаталогу.
niranjan patidar

7

Ось пара простих функцій на основі прикладу @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

Спираючись на рішення Елі Бендерського, використовуйте наступний приклад:

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>шлях до каталогу, який ви хочете пройти.


5

З повним шляхом і урахуванням шляхом буття ., .., \\, ..\\..\\subfolderі т.д .:

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

4

Здається, ця відповідь вже не існує.

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

7
Це завжди поверне порожній список, якщо ви шукаєте що-небудь, крім поточного робочого каталогу, що технічно те, що ОП прагне зробити, але не дуже багаторазове використання.
ochawkeye

2
каталоги = [x для x в os.listdir (localDir), якщо os.path.isdir (localDir + x)
Poonam

3

У мене було подібне питання недавно, і я дізнався, що найкраща відповідь для python 3.6 (як додав користувач havlock) - використовувати os.scandir. Оскільки, здається, немає рішення для його використання, я додам своє. По-перше, нерекурсивне рішення, яке перераховує лише підкаталоги безпосередньо під кореневою каталогом.

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

Рекурсивна версія виглядатиме так:

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

майте на увазі, що entry.pathце абсолютний шлях до підкаталогу. Якщо вам потрібна лише назва папки, ви можете використовувати її entry.nameзамість. Для отримання додаткових відомостей про entryоб'єкт зверніться до os.DirEntry .


Насправді, так, як це написано, не буде працювати 3,5, лише 3,6. Для використання на 3.5 необхідно видалити менеджер контексту - см stackoverflow.com/questions/41401417 / ...
havlock

Це вірно. Я міг би поклятися, що десь прочитав, що менеджер контексту був реалізований в 3.5, але, здається, я помиляюся.
Альберто А

1

використовувати функцію фільтра os.path.isdirнад os.listdir() чимось подібнимfilter(os.path.isdir,[os.path.join(os.path.abspath('PATH'),p) for p in os.listdir('PATH/')])


1

У цьому списку будуть перелічені всі підкаталоги внизу дерева файлів.

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 є новою у версії 3.4


1

Функція повернення списку всіх підкаталогів у межах заданого шляху файлу. Буде проведено пошук по всьому дереву файлів.

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

ми можемо отримати список усіх папок за допомогою os.walk ()

import os

path = os.getcwd()

pathObject = os.walk(path)

цей pathObject є об'єктом, і ми можемо отримати масив

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

Ми можемо отримати список усіх підкаталогів шляхом ітерації через arr і друку середнього масиву

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

Це надрукує весь підкаталог.

Щоб отримати всі файли:

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

0

Ця функція з даним батьком directoryповторює всі її directoriesрекурсивно і printsвсе те, filenamesщо він знаходиться всередині. Занадто корисно.

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

Приєднавшись до декількох рішень звідси, ось що я в кінцевому підсумку використовував:

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, '*')))]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.