Lấy danh sách tất cả các thư mục con trong thư mục hiện tại


559

Có cách nào để trả về một danh sách tất cả các thư mục con trong thư mục hiện tại trong Python không?

Tôi biết bạn có thể làm điều này với các tập tin, nhưng tôi cần phải có được danh sách các thư mục thay thế.


Câu trả lời:


603

Bạn có nghĩa là thư mục con ngay lập tức, hoặc mọi thư mục ngay trên cây?

Dù bằng cách nào, bạn có thể sử dụng os.walkđể làm điều này:

os.walk(directory)

sẽ mang lại một tuple cho mỗi thư mục con. Mục đầu tiên trong 3-tuple là tên thư mục, vì vậy

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

sẽ cung cấp cho bạn tất cả các thư mục con, đệ quy.

Lưu ý rằng mục nhập thứ hai trong bộ dữ liệu là danh sách các thư mục con của mục nhập ở vị trí đầu tiên, vì vậy bạn có thể sử dụng mục này thay thế, nhưng nó không có khả năng giúp bạn tiết kiệm nhiều.

Tuy nhiên, bạn có thể sử dụng nó chỉ để cung cấp cho bạn các thư mục con ngay lập tức:

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

Hoặc xem các giải pháp khác đã được đăng, sử dụng os.listdiros.path.isdir, bao gồm cả các giải pháp tại " Cách nhận tất cả các thư mục con ngay lập tức trong Python ".


7
Tôi nghĩ os.walk trả lại gấp ba lần (root, dirs, files). Điều đó có nghĩa là dirs có nhiều mục lặp lại. Có cách nào hiệu quả hơn mà đệ quy thông qua các thư mục?
mathtick

22
Không sử dụng os.walk('.').next()[1]hoặc os.walk('.').__next__()[1]trực tiếp. Thay vào đó, hãy sử dụng hàm dựng sẵn next(), có sẵn trong cả Python 2 (xem doc)Python 3 (xem doc) . Ví dụ : next(os.walk('.'))[1].
Lucio Paiva

1
@Lucio Tại sao nó là xấu khi sử dụng os.walk('.').next()[1]trực tiếp?
wvducky

8
@wvducky đó là một thực tiễn tồi vì iteraror.__next__()là một phương thức nội bộ và iterator.next()việc sử dụng nên được chuyển sang tích hợp next()theo PEP-3114. Xem PEP-3114 đã được phê duyệt vào năm 2007
Lucio Paiva

16
Đối với bất kỳ ai quan tâm về sự khác biệt về hiệu suất giữa os.walkos.listdir+ os.path.isdirgiải pháp: Tôi chỉ thử nghiệm trên một thư mục có 10.000 thư mục con (với hàng triệu tệp trong cấu trúc phân cấp bên dưới) và sự khác biệt về hiệu suất là không đáng kể. os.walk: "10 vòng, tốt nhất là 3: 44,6 msec mỗi vòng" và os.listdir+ os.path.isdir: "10 vòng, tốt nhất là 3: 45,1 msec mỗi vòng"
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
lưu ý rằng trong phương pháp này, bạn cần quan tâm đến các vấn đề abspath nếu không được thực thi trên '.'
daspostloch

4
Chỉ cần một người đứng đầu lên, nếu bạn không sử dụng các cwd ( ''), điều này sẽ không làm việc trừ khi bạn làm một os.path.jointrên ođể có được đường dẫn đầy đủ, nếu không isdir(0)sẽ luôn luôn trả về false
James McMahon

5
Có vẻ như bài viết đã được cập nhật với các bản sửa lỗi cho hai vấn đề được đề cập ở trên.
cgmb

1
Để tránh gọi os.path.joinhai lần, trước tiên bạn có thể tham gia và sau đó lọc danh sách bằng cách sử dụng os.path.isdir: filter(os.path.isdir, [os.path.join(d, o) for o in os.listdir(d)])
quant_dev

155

Bạn chỉ có thể sử dụng glob.glob

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

Đừng quên dấu vết /sau *.


Đẹp. Đơn giản. Chỉ, nó để lại dấu vết /trong tên
juanmirocks

9
Nếu bạn không thể giả sử /là trình phân tách thư mục, hãy làm điều này:glob(os.path.join(path_to_directory, "*", ""))
juanmirocks

1
Điều này không làm việc cho các thư mục con! Để sử dụng toàn cầu, đây là câu trả lời hoàn chỉnh: Sử dụng Glob () để tìm các tệp đệ quy trong Python?
poppie

1
để làm cho đệ quy toàn cầu, bạn chỉ cần thêm đối số saurecursive=True
JacoSolari

102

Đẹp hơn nhiều so với ở trên, vì bạn không cần vài os.path.join () và bạn sẽ nhận được đường dẫn đầy đủ trực tiếp (nếu bạn muốn), bạn có thể thực hiện điều này trong Python 3.5 trở lên.

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

Điều này sẽ đưa ra đường dẫn đầy đủ đến thư mục con. Nếu bạn chỉ muốn tên của thư mục con sử dụng f.namethay vìf.path

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


Hơi OT: Trong trường hợp bạn cần tất cả các thư mục con đệ quy và / hoặc tất cả các tệp đệ quy , hãy xem chức năng này, nhanh hơn os.walk& globvà sẽ trả về một danh sách tất cả các thư mục con cũng như tất cả các tệp bên trong các thư mục con (phụ) đó: https://stackoverflow.com/a/59803793/2441026

Trong trường hợp bạn chỉ muốn tất cả các thư mục con đệ quy :

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

Trả về một danh sách tất cả các thư mục con với đường dẫn đầy đủ của chúng. Điều này một lần nữa là nhanh hơn os.walkvà nhanh hơn rất nhiều glob.


Một phân tích của tất cả các chức năng

tl; dr:
- Nếu bạn muốn nhận tất cả các thư mục con ngay lập tức để sử dụng thư mục os.scandir.
- Nếu bạn muốn nhận tất cả các thư mục con, thậm chí các thư mục lồng nhau , hãy sử dụng os.walkhoặc - nhanh hơn một chút - fast_scandirchức năng trên.
- Không bao giờ chỉ sử dụng os.walkcho các thư mục con cấp cao nhất, vì nó có thể chậm hơn hàng trăm (!) Lần os.scandir.

  • Nếu bạn chạy mã bên dưới, hãy đảm bảo chạy mã một lần để hệ điều hành của bạn sẽ truy cập vào thư mục, loại bỏ kết quả và chạy thử nghiệm, nếu không kết quả sẽ bị sai lệch.
  • Bạn có thể muốn trộn lẫn các cuộc gọi chức năng, nhưng tôi đã thử nghiệm nó và nó không thực sự quan trọng.
  • Tất cả các ví dụ sẽ cung cấp đường dẫn đầy đủ đến thư mục. Ví dụ pathlib là một đối tượng Đường dẫn (Windows).
  • Phần tử đầu tiên os.walksẽ là thư mục cơ sở. Vì vậy, bạn sẽ không chỉ nhận được thư mục con. Bạn có thể sử dụng fu.pop(0)để loại bỏ nó.
  • Không có kết quả sẽ sử dụng phân loại tự nhiên . Điều này có nghĩa là kết quả sẽ được sắp xếp như sau: 1, 10, 2. Để có được sự sắp xếp tự nhiên (1, 2, 10), vui lòng xem tại https://stackoverflow.com/a/48030307/2441026


Kết quả :

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

Đã thử nghiệm với 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

Nếu bạn cần một giải pháp đệ quy sẽ tìm thấy tất cả các thư mục con trong thư mục con, hãy sử dụng đi bộ như đề xuất trước đó.

Nếu bạn chỉ cần thư mục con của thư mục hiện tại, kết hợp os.listdirvớios.path.isdir




19

Bạn có thể lấy danh sách các thư mục con (và tệp) trong Python 2.7 bằng os.listdir (đường dẫn)

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

59
Điều này bao gồm các tập tin quá.
Tarnay Kálmán

2
Tên khó hiểu vì 'dir' không đề cập đến các đối tượng hình thành danh sách mà là thư mục container. Vui lòng kiểm tra câu trả lời một dòng của bạn, đối với người mới bắt đầu, việc chọn chúng là rất hấp dẫn.
Titou

4
Cảnh giác với os.listdirdanh sách nội dung của thư mục bao gồm các tập tin.
guneysus

13

Liệt kê các thư mục chỉ

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)

Liệt kê các tệp chỉ trong thư mục hiện tại

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
Không hoạt động trên hệ điều hành mac. Tôi nghĩ rằng vấn đề là os.listdir chỉ trả về tên của thư mục chứ không phải đường dẫn đầy đủ nhưng os.path.itorir chỉ trả về True nếu đường dẫn đầy đủ là một thư mục.
denson

Điều này hoạt động bên ngoài thư mục hiện tại nếu bạn sửa đổi dòng một chút: subirs = filter (os.path.itorir, [os.path.join (dir, x) cho x trong os.listdir (dir)])
RLC

12

Python 3.4 giới thiệu các pathlibmô-đun vào thư viện chuẩn, cung cấp một cách tiếp cận hướng đối tượng để xử lý đường dẫn hệ thống tập tin:

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 cũng có sẵn trên Python 2.7 thông qua mô đun pathlib2 trên PyPi.


Để lặp lại danh sách các thư mục con, đây là một cú pháp gọn gàng, đẹp mắt:for f in filter(Path.is_dir, p.iterdir()):
Bryan Roach

11

Vì tôi đã vấp phải sự cố này khi sử dụng các đường dẫn Python 3.4 và Windows UNC, đây là một biến thể cho môi trường này:

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 là phiên bản mới trong Python 3.4 và giúp làm việc với các đường dẫn trong các hệ điều hành khác nhau dễ dàng hơn nhiều: https://docs.python.org/3.4/l Library / pathlib.html


10

Mặc dù câu hỏi này đã được trả lời từ lâu. Tôi muốn khuyên bạn nên sử dụng pathlibmô-đun vì đây là một cách mạnh mẽ để hoạt động trên hệ điều hành Windows và Unix.

Vì vậy, để có được tất cả các đường dẫn trong một thư mục cụ thể bao gồm các thư mục con:

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

Vân vân.


9

Nhờ những lời khuyên guys. Tôi gặp phải một vấn đề với các liên kết mềm (đệ quy vô hạn) được trả về dưới dạng thư mục. Liên kết mềm? Chúng tôi không muốn không có liên kết mềm của stinkin! Vì thế...

Điều này chỉ hiển thị các thư mục, không phải liên kết mềm:

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

1
Cái gì được [x[0] for x in inf]gọi là trăn để tôi có thể tra cứu nó?
shinzou

2
@shinzou Đó là một sự hiểu biết danh sách. Siêu hữu ích. Cũng tìm hiểu dict hiểu.
KurtB

9

Sao chép dán thân thiện trong ipython:

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

Đầu ra từ print(folders):

['folderA', 'folderB']

2
X trong trường hợp này là gì?
Abhishek Parikh

1
@AbhishekParikh xlà mục từ danh sách được tạo bởi os.listdir(d)listdirsẽ trả về các tệp và thư mục mà anh ta đang sử dụng filterlệnh với os.path.isdirđể lọc bất kỳ tệp nào khỏi danh sách.
James Burke

8

Đây là cách tôi làm điều đó.

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

Nó không hoạt động. Tôi đoán trong x bạn phải cung cấp đường dẫn đầy đủ để kiểm tra bằng cách sử dụng
isdir

Bạn có thể gặp rắc rối với os.getcwd (); Về cơ bản, những gì bạn có thể làm là bạn có thể có được đường dẫn tuyệt đối và sử dụng nó thay thế. dir = os.path.dirname (os.path.abspath ( tệp ))
Mujeeb Ishaque

sử dụng os, pat.join () làm việc cho tôi. Bởi vì nó đã giúp có được con đường đầy đủ của thư mục con.
niranjan patidar

7

Dưới đây là một số chức năng đơn giản dựa trên ví dụ của @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

Dựa trên giải pháp của Eli Bendersky, hãy sử dụng ví dụ sau:

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"

nơi <your_directory>là đường dẫn đến thư mục mà bạn muốn đi qua.


5

Với đường dẫn đầy đủ và chiếm con đường hạnh phúc ., .., \\, ..\\..\\subfolder, vv:

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

4

Câu trả lời này dường như không tồn tại.

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

7
Điều này sẽ luôn trả về một danh sách trống nếu bạn đang tìm kiếm bất cứ thứ gì ngoài thư mục làm việc hiện tại, về mặt kỹ thuật là những gì OP đang muốn làm, nhưng không thể tái sử dụng.
ochawkeye

2
thư mục = [x cho x trong os.listdir (localDir) nếu os.path.itorir (localDir + x)
Poonam

3

Gần đây tôi đã có một câu hỏi tương tự và tôi phát hiện ra rằng câu trả lời tốt nhất cho python 3.6 (như người dùng đã thêm havlock) là sử dụng os.scandir. Vì dường như không có giải pháp nào sử dụng nó, tôi sẽ tự thêm vào. Đầu tiên, một giải pháp không đệ quy chỉ liệt kê các thư mục con trực tiếp trong thư mục gốc.

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

Phiên bản đệ quy sẽ như thế này:

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

hãy nhớ rằng entry.pathsử dụng đường dẫn tuyệt đối đến thư mục con. Trong trường hợp bạn chỉ cần tên thư mục, bạn có thể sử dụng entry.namethay thế. Tham khảo os.DirEntry để biết thêm chi tiết về entryđối tượng.


Trên thực tế, cách viết này sẽ không hoạt động trên 3.5, chỉ 3.6. Để sử dụng trên 3.5, bạn cần xóa trình quản lý bối cảnh - xem stackoverflow.com/questions/41401417/ trên
havlock

Chính xác. Tôi có thể thề rằng tôi đã đọc ở đâu đó rằng trình quản lý bối cảnh được triển khai trong 3.5, nhưng có vẻ như tôi đã sai.
Alberto A

1

sử dụng chức năng lọc os.path.isdirtrên os.listdir() một cái gì đó như thế nàyfilter(os.path.isdir,[os.path.join(os.path.abspath('PATH'),p) for p in os.listdir('PATH/')])


1

Điều này sẽ liệt kê tất cả các thư mục con ngay xuống cây tập tin.

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 là phiên bản mới 3,4


1

Chức năng trả về Danh sách tất cả các thư mục con trong một đường dẫn tệp đã cho. Sẽ tìm kiếm thông qua toàn bộ cây tập tin.

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

chúng ta có thể lấy danh sách tất cả các thư mục bằng cách sử dụng os.walk ()

import os

path = os.getcwd()

pathObject = os.walk(path)

này pathObject là một đối tượng và chúng tôi có thể nhận được một mảng bằng

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

Chúng tôi có thể nhận được danh sách tất cả các thư mục con bằng cách duyệt qua arr và in mảng giữa

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

Điều này sẽ in tất cả các thư mục con.

Để có được tất cả các tập tin:

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

0

Hàm này, với một cha mẹ đã cho directorylặp đi lặp lại trên tất cả directoriesđệ quy của nó và printstất cả những filenamesgì nó tìm thấy bên trong. Quá hữu ích.

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

Bằng cách tham gia nhiều giải pháp từ đây, đây là những gì tôi đã sử dụng:

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, '*')))]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.