Getting a list of all subdirectories in the current directory

后端 未结 29 2903
一个人的身影
一个人的身影 2020-11-22 08:02

Is there a way to return a list of all the subdirectories in the current directory in Python?

I know you can do this with files, but I need to get the list of direct

29条回答
  •  清歌不尽
    2020-11-22 08:31

    Much nicer than the above, because you don't need several os.path.join() and you will get the full path directly (if you wish), you can do this in Python 3.5 and above.

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

    This will give the complete path to the subdirectory. If you only want the name of the subdirectory use f.name instead of f.path

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


    Slightly OT: In case you need all subfolder recursively and/or all files recursively, have a look at this function, that is faster than os.walk & glob and will return a list of all subfolders as well as all files inside those (sub-)subfolders: https://stackoverflow.com/a/59803793/2441026

    In case you want only all subfolders recursively:

    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
    

    Returns a list of all subfolders with their full paths. This again is faster than os.walk and a lot faster than glob.


    An analysis of all functions

    tl;dr:
    - If you want to get all immediate subdirectories for a folder use os.scandir.
    - If you want to get all subdirectories, even nested ones, use os.walk or - slightly faster - the fast_scandir function above.
    - Never use os.walk for only top-level subdirectories, as it can be hundreds(!) of times slower than os.scandir.

    • If you run the code below, make sure to run it once so that your OS will have accessed the folder, discard the results and run the test, otherwise results will be screwed.
    • You might want to mix up the function calls, but I tested it, and it did not really matter.
    • All examples will give the full path to the folder. The pathlib example as a (Windows)Path object.
    • The first element of os.walk will be the base folder. So you will not get only subdirectories. You can use fu.pop(0) to remove it.
    • None of the results will use natural sorting. This means results will be sorted like this: 1, 10, 2. To get natural sorting (1, 2, 10), please have a look at https://stackoverflow.com/a/48030307/2441026


    Results:

    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
    

    Tested with W7x64, Python 3.8.1.

    # -*- coding: utf-8 -*-
    # Python 3
    
    
    import time
    import os
    from glob import glob
    from pathlib import Path
    
    
    directory = r""
    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()
    

提交回复
热议问题