Получение списка всех подкаталогов в текущем каталоге

560

Есть ли способ вернуть список всех подкаталогов в текущем каталоге в Python?

Я знаю, что вы можете сделать это с файлами, но мне нужно получить список каталогов вместо этого.

Брэд зейс
источник

Ответы:

604

Вы имеете в виду непосредственные подкаталоги или каждый каталог прямо в дереве?

В любом случае, вы можете использовать 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, files). Что означает, что у dirs много повторяющихся записей. Есть ли более эффективный способ, который повторяется через каталоги?
математика
22
Не использовать os.walk('.').next()[1]или os.walk('.').__next__()[1]напрямую. Вместо этого используйте встроенную функцию next(), которая доступна как в Python 2 (см. Документ), так и в Python 3 (см. Документ) . Например: next(os.walk('.'))[1].
Лусио Пайва
1
@Lucio Почему это плохо использовать os.walk('.').next()[1]напрямую?
Висбуки
8
@wisbucky это плохая практика, потому что iteraror.__next__()это внутренний метод и iterator.next()использование должно быть переведено на встроенный в next()соответствии с PEP-3114. См. PEP-3114, который был утвержден в 2007 году.
Lucio Paiva
16
Для всех, кто обеспокоен разницей в производительности между решениями os.walkи os.listdir+ os.path.isdir: я только что протестировал каталог с 10 000 подкаталогов (с миллионами файлов в иерархии ниже), и различия в производительности незначительны. 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))]
gahooa
источник
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/*/")

Не забывайте отставать /после *.

Удит Бансал
источник
Ницца. Просто. Только, он оставляет /
след
9
Если вы не можете считать /себя разделителем папок, сделайте следующее:glob(os.path.join(path_to_directory, "*", ""))
juanmirocks
1
Это не работает для подкаталогов! Чтобы использовать glob, вот полный ответ: Используйте 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.

  • Если вы запустите приведенный ниже код, обязательно запустите его один раз, чтобы ваша ОС получила доступ к папке, отменила результаты и запустила тест, иначе результаты будут испорчены.
  • Возможно, вы захотите перепутать вызовы функций, но я проверил это, и это не имело значения.
  • Все примеры приведут полный путь к папке. Пример pathlib в качестве объекта пути (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()
user136036
источник
35

Если вам нужно рекурсивное решение, которое найдет все подкаталоги в подкаталогах, используйте walk, как предлагалось ранее.

Если вам нужны только дочерние каталоги текущего каталога, объедините os.listdirсos.path.isdir

Эли Бендерский
источник
23

Реализовал это используя 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)
Харит Де Сильва
источник
19

Вы можете получить список подкаталогов (и файлов) в Python 2.7, используя os.listdir (путь)

import os
os.listdir(path)  # list of subdirectories and files
Оскар Мартин
источник
59
Это включает в себя файлы тоже.
Tarnay Kálmán
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)
NutJobb
источник
2
Не работал на Mac OS. Я думаю, что проблема в том, что os.listdir возвращает только имя каталога, а не полный путь, но os.path.isdir возвращает True только в том случае, если полный путь является каталогом.
Denson
Это работает за пределами текущего каталога, если вы слегка измените строку: subdirs = filter (os.path.isdir, [os.path.join (dir, x) для x в 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.

joelostblom
источник
Чтобы перебрать список подкаталогов, вот хороший, чистый синтаксис: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

Спасибо за советы ребята. Я столкнулся с проблемой с программными ссылками (бесконечная рекурсия), возвращаемыми как dirs. Softlinks? Мы не хотим никаких вонючих мягких ссылок! Так...

Это делает только каталоги, а не программные ссылки:

>>> import os
>>> inf = os.walk('.')
>>> [x[0] for x in inf]
['.', './iamadir']
KurtB
источник
1
Что [x[0] for x in inf]называется в Python, чтобы я мог посмотреть?
Синдзоу
2
@shinzou Это понимание списка. Супер полезно. Также посмотрите, что вы понимаете.
KurtB
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 ( файл ))
Муджиб Исак
используя os, pat.join () работал для меня. Потому что это помогло получить полный путь к подкаталогу.
Ниранджан Патидар
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>путь к каталогу, который вы хотите пройти.

Blairg23
источник
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))])
DevPlayer
источник
4

Этот ответ, кажется, уже не существует.

directories = [ x for x in os.listdir('.') if os.path.isdir(x) ]
Энди
источник
7
Это всегда будет возвращать пустой список, если вы ищете что-то кроме текущего рабочего каталога, что технически то, что ОП хочет сделать, но не очень многоразово.
ochawkeye
2
directoryies = [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вместо этого. Обратитесь к os.DirEntry для получения дополнительной информации об entryобъекте.

Альберто А
источник
На самом деле, как это написано, это не будет работать на 3.5, только 3.6. Для использования на 3.5 необходимо удалить менеджер контекста - см stackoverflow.com/questions/41401417/...
havlock
Это правильно. Могу поклясться, что где-то читал, что менеджер контекста был реализован в 3.5, но, похоже, я не прав.
Альберто A
1

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

oneLeggedChicken
источник
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

Yossarian42
источник
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 ;")
DBZ
источник
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, '*')))]
SadSeven
источник