Python中检查目录是否为空的最快方法是什么?

4
我在一台Windows机器上工作,想要检查网络路径上的目录是否为空。 首先想到的是调用os.listdir()函数并检查其长度是否为0。 即:
def dir_empty(dir_path):
    return len(os.listdir(dir_path)) == 0

因为这是一个网络路径,我并不总是有良好的连接,并且一个文件夹可能含有成千上万个文件,所以这是一种非常缓慢的解决方案。是否有更好的解决方案?


1
我实际上不认为这是重复的。我想知道Python的答案,而不是Shell的答案。 - rob
1
https://dev59.com/9FUM5IYBdhLWcg3wINak - Sid
6个回答

6
到目前为止我发现的最快解决方案是:
def dir_empty(dir_path):
    return not any((True for _ in os.scandir(dir_path)))

或者,正如下面评论中提出的那样:
def dir_empty(dir_path):
    return not next(os.scandir(dir_path), None)

在我使用的较慢的网络上,这个操作只需要几秒钟而不是分钟级别(对于os.listdir()版本需要几分钟)。这似乎更快,因为any语句只会评估第一个True语句。

这会遍历dir_path中的每个文件。相反,尝试使用:return not next(os.scandir(dirpath), None) - SurpriseDog
[True for _ in os.scandir(dir_path)] 在内存中创建了一个列表推导式,看起来像是 [True, True, True, True](每个 scandir 条目都有一个命中),然后 any 遍历这个 True 列表。 - SurpriseDog
https://dev59.com/AHVD5IYBdhLWcg3wOo9h - SurpriseDog
1
升级了,真奇怪它居然提高了我的速度。我会调整答案的。谢谢你指出这个问题。 - rob

4
自 Python 3.4 开始,您可以使用 pathlib.iterdir() 方法,它将生成目录内容的路径对象。
>>> from pathlib import Path
>>>
>>> def dir_empty(dir_path):
...     path = Path(dir_path)
...     has_next = next(path.iterdir(), None)
...     if has_next is None:
...             return True
...     return False

3

由于OP询问的是最快的方法,我认为使用os.scandir并在找到第一个文件后立即返回应该是最快的。 os.scandir 返回一个迭代器。我们应该避免创建整个列表来检查它是否为空。

测试目录包含约10万个文件:

from pathlib import Path    
import os

path = 'jav/av'
len(os.listdir(path))

>>> 101204

然后开始我们的测试:
def check_empty_by_scandir(path):
    with os.scandir(path) as it:
        return not any(it)
    
def check_empty_by_listdir(path):
    return not os.listdir(path)

def check_empty_by_pathlib(path):
    return not any(Path(path).iterdir())


%timeit check_empty_by_scandir(path)
>>> 179 µs ± 878 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit check_empty_by_listdir(path)
>>> 28 ms ± 185 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit check_empty_by_pathlib(path)
>>> 27.6 ms ± 140 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

正如我们所看到的,check_empty_by_listdircheck_empty_by_pathlibcheck_empty_by_scandir慢了大约155倍。os.listdir()和Path.iterdir()返回的结果相同,因为Path.iterdir()在后台使用os.listdir(),从而在内存中创建一个完整的列表。

此外,正如人们指出的那样,在Linux中,阅读os.stat不是一个选项,它将在空目录中返回4096。


3

listdir 返回一个列表。scandir 返回一个迭代器,可能更加高效。

def dir_empty(dir_path):
    try:
        next(os.scandir(dir_path))
        return False
    except StopIteration:
        return True

肯定更易读,因为我可以猜测每行的作用,而在 def check_empty_by_scandir(path): \n with os.scandir(path) as it: \n return not any(it) 中,我必须知道 any 的工作原理。 - DangerMouse

1

在Windows操作系统中,有一个名为PathIsDirectoryEmptyA的函数。我们可以使用它来检查文件夹是否为空。

def is_dir_empty(path:str)->bool:
    import ctypes
    shlwapi = ctypes.OleDLL('shlwapi')
    return shlwapi.PathIsDirectoryEmptyA(path.encode('utf-8'))

-1

使用os.stat

is_empty = os.stat(dir_path).st_size == 0

使用Python的pathlib
from pathlib import Path

is_empty = Path(dir_path).stat().st_size == 0

1
在一个开箱即用的 ext4 文件系统上,空目录的 st_size == 4096 - Han-Kwang Nienhuys

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接