有没有办法在Python中返回当前目录中所有子目录的列表?
我知道可以获取文件列表,但我需要获取目录列表。
有没有办法在Python中返回当前目录中所有子目录的列表?
我知道可以获取文件列表,但我需要获取目录列表。
你是指立即子目录还是整个树下的每个目录?无论哪种方式,你都可以使用os.walk
来实现:
os.walk(directory)
将为每个子目录生成一个元组。3-tuple中的第一个条目是目录名称,因此
[x[0] for x in os.walk(directory)]
这应该会递归地给你所有的子目录。
请注意,元组中第二个条目是第一个位置的入口的子目录列表,所以你可以使用它代替,但这不太可能节省很多时间。
但是,你可以使用它来仅获取直接子目录:
next(os.walk('.'))[1]
或者查看已经发布的其他解决方案,使用 os.listdir
和os.path.isdir
,包括在 "如何在Python中获取所有直接子目录" 中的那些解决方案。os.walk
和os.listdir
+ os.path.isdir
方法之间的性能差异:我刚在一个有10,000个子目录(包含数百万个文件)的目录上进行了测试,性能差异可以忽略不计。os.walk
方法: "10次循环,每次44.6毫秒" 和 os.listdir
+os.path.isdir
方法:"10次循环,每次45.1毫秒"。 - kevinmickeos.walk
应该击败os.listdir
+ os.path.isdir
,尤其是在网络驱动器上。原因:1)os.walk
是惰性的;如果您执行next(os.walk('.'))[1]
,它将执行单个目录列表并按目录/非目录进行分类,然后消失。设置生成器的成本是非零的,但与文件系统访问的成本完全无关。2)从3.5开始,os.walk
通过os.scandir
实现,它不需要每个条目的stat
调用来对目录/非目录进行分类(除符号链接外)... - ShadowRangeros.walk
会输给正确使用的os.scandir
(例如[e.path for e in os.scandir('.') if e.is_dir()]
这样极简),但只是因为它有一些额外的包装开销,以允许递归和单独存储非目录list
,但这两者都没有被用到; 它不执行任何其他的系统调用工作,所以无论是网络驱动器还是其他情况,费用中最大的部分(驱动器延迟,稍微小一些的系统调用开销)仍然比3.5版本以上的os.listdir+os.path.isdir
更便宜。 - ShadowRanger你可以直接使用 glob.glob
from glob import glob
glob("/path/to/directory/*/", recursive = True)
在*
后面不要忘记加上尾随的/
。
/
为文件夹分隔符,请执行以下操作:glob(os.path.join(path_to_directory, "*", ""))
。 - juanmirocksrecursive=True
。 - JacoSolari这种方法比上面的方法更好,因为你不需要多次使用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://dev59.com/OmMl5IYBdhLWcg3wcmvD#59803793
如果您只想要递归地获取所有子文件夹: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
慢数百倍!
os.walk
的第一个元素将是基础文件夹。因此,您将不仅获得子目录。您可以使用fu.pop(0)
来删除它。结果:
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
# -*- 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()
pathlib
:[f for f in p.iterdir() if f.is_dir()]
。 - Charlie Parkerfast_scandir
,但它需要一个多小时的时间。这正常吗?有什么方法可以加快速度吗? - Vincentimport os
d = '.'
[os.path.join(d, o) for o in os.listdir(d)
if os.path.isdir(os.path.join(d,o))]
o
上做一个 os.path.join
获取完整路径,否则 isdir(0)
将始终返回 false。 - James McMahonos.path.join
,您可以先使用 os.path.join
拼接路径,然后再使用 os.path.isdir
过滤列表:filter(os.path.isdir, [os.path.join(d, o) for o in os.listdir(d)])
- quant_dev[f for f in data_path.iterdir() if f.is_dir()]
或glob一起使用更简单易读:glob.glob("/path/to/directory/*/")
。 - Charlie Parkerpathlib
模块到标准库中,它提供了一种面向对象的处理文件系统路径的方法:from pathlib import Path
p = Path('./')
# All subdirectories in the current directory, not recursive.
[f for f in p.iterdir() if f.is_dir()]
**
模式。
# This will also include the current directory '.'
list(p.glob('**'))
*
会包括非递归的文件和目录。要仅获取目录,请添加尾随/
,但这仅适用于直接使用glob库时,而不是通过pathlib使用glob库时。import glob
# These three lines return both files and directories
list(p.glob('*'))
list(p.glob('*/'))
glob.glob('*')
# Whereas this returns only directories
glob.glob('*/')
Path('./').glob('**')
与glob.glob('**/', recursive=True)
匹配的路径相同。for f in filter(Path.is_dir, p.iterdir()):
- Bryan Roachglob(*/)
不足以满足需求吗?无论如何,这是一个绝妙的答案,特别是你干净利落地使用了 pathlib
。如果它也允许递归,那么评论一下会很好,尽管从问题的标题来看这不是必需的,未来的读者应该阅读你链接的文档。 - Charlie Parker**
不需要尾随斜杠)。关于使用单个星号,这将非递归地匹配文件和目录。 - joelostblomglob.glob('**/', recursive=True)
不会包含隐藏目录,但是 Path('./').glob('**')
会。 - nossorted()
,以便返回的列表是排序的...根据使用情况可能有用也可能没用。 - Matias Andinapathlib
更简单:[f for f in p.iterdir() if f.is_dir()]
。 - Charlie Parkerpathlib
出现早几年。 - Eli Benderskyprint("\nWe are listing out only the directories in current directory -")
directories_in_curdir = list(filter(os.path.isdir, os.listdir(os.curdir)))
print(directories_in_curdir)
files = list(filter(os.path.isfile, os.listdir(os.curdir)))
print("\nThe following are the list of all files in the current directory -")
print(files)
isdir
来解决这个问题。 - Sridhar Sarnobat我更喜欢使用filter函数(https://docs.python.org/2/library/functions.html#filter),不过这只是个人口味而已。
d='.'
filter(lambda x: os.path.isdir(os.path.join(d, x)), os.listdir(d))
pathlib
更简单:[f for f in p.iterdir() if f.is_dir()]
- Charlie Parker使用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)
pathlib
更简单:[f for f in p.iterdir() if f.is_dir()]
- Charlie Parker您可以使用Python 2.7中的os.listdir(path)
获取子目录(和文件)列表。
import os
os.listdir(path) # list of subdirectories and files
os.listdir
列出目录中的内容,包括文件。 - guneysus
[f for f in data_path.iterdir() if f.is_dir()]
。这将返回文件夹名称作为字符串,还会自动排除.
和..
,非常感谢。另外,glob.glob解决方案也很有价值:glob.glob("/path/to/directory/*/")
。 - Charlie Parker