获取当前目录下所有子目录的列表
有没有办法在Python中返回当前目录下所有子目录的列表呢?
我知道可以获取文件的列表,但我需要的是目录的列表。
35 个回答
这个方法比上面的要好很多,因为你不需要写很多次 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://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
也快很多。
对所有函数的分析
总结一下:
- 如果你想获取一个文件夹的所有直接子目录,使用 os.scandir
。
- 如果你想获取所有子目录,包括嵌套的子目录,使用 os.walk
或者稍微快一点的 fast_scandir
函数。
- 不要只用 os.walk
来获取顶层子目录,因为它的速度可能比 os.scandir
慢上百倍!
- 如果你运行下面的代码,确保先运行一次,这样你的操作系统才能访问到这个文件夹,丢弃结果后再进行测试,否则结果会不准确。
- 你可能想要混合调用这些函数,但我测试过,这样做其实没什么影响。
- 所有示例都会给出文件夹的完整路径。pathlib 示例会返回一个 (Windows)Path 对象。
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()
你可以直接使用 glob.glob
这个方法。
from glob import glob
glob("/path/to/directory/*/", recursive = True)
别忘了在 *
后面加一个斜杠 /
。
你是问直接的子目录,还是树形结构下的所有目录呢?
无论哪种情况,你都可以使用 os.walk
来实现这个功能:
os.walk(directory)
这个方法会为每个子目录返回一个元组。这个三元组的第一个元素是目录的名字,所以
[x[0] for x in os.walk(directory)]
应该能给你所有的子目录,递归地获取。
需要注意的是,元组中的第二个元素是第一个位置的目录的子目录列表,所以你也可以用这个来获取,但这样做可能不会节省太多时间。
不过,你可以用它来获取直接的子目录:
next(os.walk('.'))[1]
或者你也可以查看已经发布的其他解决方案,使用 os.listdir
和 os.path.isdir
,包括那些在 "如何获取Python中的所有直接子目录" 的帖子中提到的。