Mendapatkan daftar semua subdirektori di direktori saat ini

Jawaban:

604

Apakah maksud Anda subdirektori langsung, atau setiap direktori di bawah pohon?

Apa pun itu, Anda dapat menggunakannya os.walkuntuk melakukan ini:

os.walk(directory)

akan menghasilkan tuple untuk setiap subdirektori. Entri pertama dalam 3-tuple adalah nama direktori, jadi

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

seharusnya memberi Anda semua subdirektori, secara rekursif.

Perhatikan bahwa entri kedua dalam tuple adalah daftar direktori anak dari entri di posisi pertama, jadi Anda bisa menggunakan ini sebagai gantinya, tetapi sepertinya tidak akan banyak menghemat.

Namun, Anda bisa menggunakannya hanya untuk memberi Anda direktori anak langsung:

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

Atau lihat solusi lain yang sudah diposting, menggunakan os.listdirdan os.path.isdir, termasuk yang ada di " Cara mendapatkan semua subdirektori langsung dengan Python ".

Blair Conrad
sumber
7
Saya pikir os.walk mengembalikan tiga kali lipat (root, dir, file). Yang berarti bahwa dir memiliki banyak entri berulang. Apakah ada cara yang lebih efisien yang berulang melalui direktori?
mathtick
22
Jangan gunakan os.walk('.').next()[1]atau os.walk('.').__next__()[1]langsung. Sebagai gantinya, gunakan fungsi bawaan next(), yang tersedia baik dalam Python 2 (lihat doc) dan Python 3 (lihat doc) . Sebagai contoh: next(os.walk('.'))[1].
Lucio Paiva
1
@ Lucio Mengapa itu buruk untuk digunakan os.walk('.').next()[1]secara langsung?
wisbucky 2-15
8
@wisbucky ini adalah praktik yang buruk karena iteraror.__next__()merupakan metode internal dan iterator.next()penggunaan harus dialihkan ke bawaan next()menurut PEP-3114. Lihat PEP-3114 yang disetujui pada 2007.
Lucio Paiva
16
Bagi siapa pun yang peduli tentang perbedaan kinerja antara os.walkdan os.listdir+ os.path.isdirsolusi: Saya baru saja menguji pada direktori dengan 10.000 subdirektori (dengan jutaan file dalam hierarki di bawah) dan perbedaan kinerja dapat diabaikan. os.walk: "10 loop, terbaik 3: 44,6 msec per loop" dan os.listdir+ os.path.isdir: "10 loop, terbaik dari 3: 45,1 msec per loop"
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
sumber
5
perhatikan bahwa dalam pendekatan ini Anda perlu menangani masalah abspath jika tidak dieksekusi pada '.'
daspostloch
4
Hanya kepala, jika Anda tidak menggunakan cwd ('.'), Ini tidak akan berfungsi kecuali jika Anda melakukan os.path.joinon ountuk mendapatkan path lengkap, jika tidak isdir(0)akan selalu kembali salah
James McMahon
5
Tampaknya pos telah diperbarui dengan perbaikan untuk dua masalah yang disebutkan di atas.
cgmb
1
Untuk menghindari panggilan os.path.joindua kali, Anda dapat bergabung terlebih dahulu dan kemudian menyaring daftar menggunakan os.path.isdir: filter(os.path.isdir, [os.path.join(d, o) for o in os.listdir(d)])
quant_dev
155

Anda bisa menggunakannya glob.glob

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

Jangan lupa jejak /setelah *.

Udit Bansal
sumber
Bagus. Sederhana. Hanya, ia meninggalkan /
jejak
9
Jika Anda tidak dapat menganggap /sebagai pemisah folder, lakukan ini:glob(os.path.join(path_to_directory, "*", ""))
juanmirocks
1
Ini tidak berfungsi untuk subdirektori! Untuk menggunakan glob, inilah jawaban lengkapnya: Gunakan Glob () untuk menemukan file secara rekursif dalam Python?
poppie
1
untuk membuat glob rekursif Anda bisa menambahkan argumen berikutrecursive=True
JacoSolari
102

Jauh lebih bagus daripada yang di atas, karena Anda tidak perlu beberapa os.path.join () dan Anda akan mendapatkan path lengkap secara langsung (jika Anda mau), Anda dapat melakukan ini dengan Python 3.5 dan lebih tinggi.

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

Ini akan memberikan path lengkap ke subdirektori. Jika Anda hanya ingin menggunakan nama subdirektori f.namedaripadaf.path

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


Sedikit Sl: Jika Anda membutuhkan semua subfolder secara rekursif dan / atau semua file secara rekursif , lihat fungsi ini, yang lebih cepat dari os.walk& globdan akan mengembalikan daftar semua subfolder serta semua file di dalam subfolder (sub-): https://stackoverflow.com/a/59803793/2441026

Jika Anda hanya menginginkan semua subfolder secara rekursif :

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

Mengembalikan daftar semua subfolder dengan jalur lengkapnya. Ini lagi lebih cepat daripada os.walkdan jauh lebih cepat daripada glob.


Analisis semua fungsi

tl; dr:
- Jika Anda ingin mendapatkan semua subdirektori langsung untuk penggunaan folder os.scandir.
- Jika Anda ingin mendapatkan semua subdirektori, bahkan yang bersarang , gunakan os.walkatau - sedikit lebih cepat - fast_scandirfungsi di atas.
- Jangan pernah gunakan os.walkhanya untuk subdirektori tingkat atas, karena bisa jadi ratusan (!) Kali lebih lambat daripada os.scandir.

  • Jika Anda menjalankan kode di bawah ini, pastikan untuk menjalankannya sekali sehingga OS Anda akan mengakses folder, membuang hasil dan menjalankan tes, jika tidak hasilnya akan kacau.
  • Anda mungkin ingin mencampur panggilan fungsi, tapi saya mengujinya, dan itu tidak masalah.
  • Semua contoh akan memberikan path lengkap ke folder. Contoh pathlib sebagai objek Path (Windows).
  • Elemen pertama os.walkakan menjadi folder dasar. Jadi, Anda tidak hanya akan mendapatkan subdirektori. Anda dapat menggunakannya fu.pop(0)untuk menghapusnya.
  • Tidak ada hasil yang akan menggunakan penyortiran alami . Ini berarti hasil akan diurutkan seperti ini: 1, 10, 2. Untuk mendapatkan penyortiran alami (1, 2, 10), silakan lihat di https://stackoverflow.com/a/48030307/2441026


Hasil :

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

Diuji dengan 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()
pengguna136036
sumber
35

Jika Anda membutuhkan solusi rekursif yang akan menemukan semua subdirektori di subdirektori, gunakan walk seperti yang disarankan sebelumnya.

Jika Anda hanya perlu direktori anak direktori saat ini, gabungkan os.listdirdenganos.path.isdir

Eli Bendersky
sumber
23

Diimplementasikan ini menggunakan 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
sumber
19

Anda bisa mendapatkan daftar subdirektori (dan file) di Python 2.7 menggunakan os.listdir (path)

import os
os.listdir(path)  # list of subdirectories and files
Oscar Martin
sumber
59
Ini termasuk file juga.
Tarnay Kálmán
2
Nama ini membingungkan karena 'dir' tidak merujuk pada objek yang membentuk daftar tetapi ke direktori kontainer. Silakan periksa jawaban satu baris Anda, untuk pemula sangat menggoda untuk memilihnya.
Titou
4
Hati-hati dengan os.listdirdaftar isi direktori termasuk file.
guneysus
13

Hanya Mendaftar direktori

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)

Cantumkan hanya file dalam direktori saat ini

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
sumber
2
Tidak berfungsi di mac OS. Saya pikir masalahnya adalah bahwa os.listdir hanya mengembalikan nama direktori dan bukan path lengkap tetapi os.path.isdir hanya mengembalikan True jika path lengkap adalah direktori.
denson
Ini berfungsi di luar direktori saat ini jika Anda sedikit memodifikasi baris: subdirs = filter (os.path.isdir, [os.path.join (dir, x) untuk x di os.listdir (dir)])
RLC
12

Python 3.4 diperkenalkan pada pathlibmodul ke dalam perpustakaan standar, yang menyediakan pendekatan berorientasi objek untuk jalur menangani filesystem:

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 juga tersedia di Python 2.7 melalui modul pathlib2 di PyPi.

joelostblom
sumber
Untuk beralih ke daftar subdirektori, berikut adalah sintaksis yang bagus dan bersih:for f in filter(Path.is_dir, p.iterdir()):
Bryan Roach
11

Karena saya menemukan masalah ini menggunakan jalur Python 3.4 dan Windows UNC, inilah varian untuk lingkungan ini:

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 baru di Python 3.4 dan membuat bekerja dengan jalur di bawah berbagai OS jauh lebih mudah: https://docs.python.org/3.4/library/pathlib.html

Marcus Schommler
sumber
10

Meskipun pertanyaan ini dijawab sejak lama. Saya ingin merekomendasikan untuk menggunakan pathlibmodul ini karena ini adalah cara yang kuat untuk bekerja pada Windows dan Unix OS.

Jadi untuk mendapatkan semua jalur dalam direktori tertentu termasuk subdirektori:

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

dll.

Joost Döbken
sumber
9

Terima kasih untuk tipsnya, kawan. Saya mengalami masalah dengan softlink (rekursi tak terbatas) yang dikembalikan sebagai dir. Softlink? Kami tidak ingin ada tautan lunak yang menyebalkan! Begitu...

Ini hanya menghasilkan dir, bukan softlink:

>>> import os
>>> inf = os.walk('.')
>>> [x[0] for x in inf]
['.', './iamadir']
KurtB
sumber
1
Apa yang [x[0] for x in inf]disebut dengan python sehingga saya bisa mencarinya?
shinzou
2
@ Shinzou Itu daftar pemahaman. Sangat berguna. Lihat juga pemahaman dict.
KurtB
9

Copy paste friendly di ipython:

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

Output dari print(folders):

['folderA', 'folderB']
Andrew Schreiber
sumber
2
Apa X dalam kasus ini?
Abhishek Parikh
1
@AbhishekParikh xadalah item dari daftar yang dibuat oleh os.listdir(d)karena listdirakan mengembalikan file dan folder yang dia gunakan dengan filterperintah os.path.isdiruntuk menyaring file apa pun dari daftar.
James Burke
8

Beginilah cara saya melakukannya.

    import os
    for x in os.listdir(os.getcwd()):
        if os.path.isdir(x):
            print(x)
Mujeeb Ishaque
sumber
Itu tidak bekerja. Saya kira di x Anda harus memberikan path lengkap untuk memeriksa menggunakan isdir ()
niranjan patidar
Anda mungkin mengalami masalah dengan os.getcwd (); Pada dasarnya, yang dapat Anda lakukan adalah Anda bisa mendapatkan jalur absolut dan menggunakannya sebagai gantinya. dir = os.path.dirname (os.path.abspath ( file ))
Mujeeb Ishaque
menggunakan os, pat.join () bekerja untuk saya. Karena itu membantu untuk mendapatkan path penuh subdirektori.
niranjan patidar
7

Berikut adalah beberapa fungsi sederhana berdasarkan contoh @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
sumber
6

Membangun solusi Eli Bendersky, gunakan contoh berikut:

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"

di mana <your_directory>jalur ke direktori yang ingin Anda lintasi.

Blairg23
sumber
5

Jalur jalan yang penuh dan akuntansi untuk jalur makhluk ., .., \\, ..\\..\\subfolder, dll:

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

Jawaban ini sepertinya belum ada.

directories = [ x for x in os.listdir('.') if os.path.isdir(x) ]
Andy
sumber
7
Ini akan selalu mengembalikan daftar kosong jika Anda mencari apa pun selain direktori kerja saat ini, yang secara teknis adalah apa yang ingin dilakukan OP, tetapi tidak dapat digunakan kembali.
ochawkeye
2
direktori = [x untuk x dalam os.listdir (localDir) jika os.path.isdir (localDir + x)
Poonam
3

Saya punya pertanyaan serupa baru-baru ini, dan saya menemukan bahwa jawaban terbaik untuk python 3.6 (seperti yang ditambahkan pengguna havlock) adalah menggunakan os.scandir. Karena sepertinya tidak ada solusi menggunakannya, saya akan menambahkan sendiri. Pertama, solusi non-rekursif yang hanya mencantumkan subdirektori langsung di bawah direktori root.

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

Versi rekursif akan terlihat seperti ini:

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

perlu diingat bahwa entry.pathmemegang jalur absolut ke subdirektori. Jika Anda hanya perlu nama folder, Anda dapat menggunakannya entry.name. Lihat os.DirEntry untuk detail tambahan tentang entryobjek.

Alberto A
sumber
Sebenarnya, cara ini ditulis tidak akan berfungsi pada 3,5, hanya 3,6. Untuk menggunakan pada 3.5 Anda perlu menghapus manajer konteks - lihat stackoverflow.com/questions/41401417/…
havlock
Ini benar. Saya berani bersumpah saya membaca di suatu tempat bahwa manajer konteks diimplementasikan dalam 3,5, tetapi tampaknya saya salah.
Alberto A
1

gunakan fungsi filter os.path.isdiratas os.listdir() sesuatu seperti inifilter(os.path.isdir,[os.path.join(os.path.abspath('PATH'),p) for p in os.listdir('PATH/')])

oneLeggedChicken
sumber
1

Ini akan mencantumkan semua subdirektori di bawah pohon file.

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 baru dalam versi 3.4

Yossarian42
sumber
1

Berfungsi untuk mengembalikan Daftar semua subdirektori dalam jalur file yang diberikan. Akan mencari melalui seluruh pohon file.

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

kita bisa mendapatkan daftar semua folder dengan menggunakan os.walk ()

import os

path = os.getcwd()

pathObject = os.walk(path)

pathObject ini adalah objek dan kita bisa mendapatkan array dengan

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

Kita bisa mendapatkan daftar semua subdirektori dengan mengulangi melalui arr dan mencetak array tengah

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

Ini akan mencetak semua subdirektori.

Untuk mendapatkan semua file:

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

Fungsi ini, dengan orangtua yang diberikan directoryiterates atas semua secara directoriesrekursif dan printssemua filenamesyang ditemukan di dalamnya. Terlalu berguna

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
sumber
0

Dengan bergabung dengan beberapa solusi dari sini, inilah yang akhirnya saya gunakan:

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
sumber