Получение списка всех подкаталогов в текущем каталоге
Есть ли способ вернуть список всех подкаталогов в текущем каталоге в Python?
Я знаю, что вы можете сделать это с файлами, но вместо этого мне нужно получить список каталогов.
Переведено автоматически
Ответ 1
Вы имеете в виду непосредственные подкаталоги или каждый каталог прямо по дереву?
В любом случае, вы могли бы использовать os.walk
для этого:
os.walk(directory)
выдаст кортеж для каждого подкаталога. Первая запись в 3-м кортеже - это имя каталога, поэтому
[x[0] for x in os.walk(directory)]
должно предоставить вам все подкаталоги рекурсивно.
Обратите внимание, что вторая запись в кортеже - это список дочерних каталогов записи на первой позиции, поэтому вы могли бы использовать это вместо, но вряд ли это сильно сэкономит вам.
Однако вы могли бы использовать его только для предоставления вам непосредственных дочерних каталогов:
next(os.walk('.'))[1]
Или ознакомьтесь с другими уже опубликованными решениями, используя os.listdir
и os.path.isdir
, в том числе в разделе "Как получить все непосредственные подкаталоги в Python".
Ответ 2
Вы могли бы просто использовать glob.glob
from glob import glob
glob("/path/to/directory/*/", recursive = True)
Не забудьте о конце /
после *
.
Ответ 3
Намного приятнее, чем вышеописанное, потому что вам не нужно несколько 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
Немного О том, что: в случае, если вам нужны все вложенные папки рекурсивно и / или все файлы рекурсивно, взгляните на эту функцию, которая быстрее, чем os.walk
& glob
и вернет список всех вложенных папок, а также всех файлов внутри этих (вложенных)папок: https://pythonly.ru/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 в виде объекта Path (Windows).
- Первым элементом
os.walk
будет базовая папка. Таким образом, вы получите не только подкаталоги. Вы можете использоватьfu.pop(0)
, чтобы удалить его. - Ни в одном из результатов не будет использоваться естественная сортировка. Это означает, что результаты будут отсортированы следующим образом: 1, 10, 2. Чтобы получить естественную сортировку (1, 2, 10), пожалуйста, взгляните на https://pythonly.ru/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()
Ответ 4
import os
d = '.'
[os.path.join(d, o) for o in os.listdir(d)
if os.path.isdir(os.path.join(d,o))]