【问题标题】:Iterate over a very large number of files in a folder遍历文件夹中的大量文件
【发布时间】:2013-06-10 09:11:57
【问题描述】:

当目录中的文件数大于 2.500.000 时,使用 NTFS 和 Windows 7 遍历目录中所有文件的最快方法是什么? 所有文件都在顶级目录下。

目前我使用

for root, subFolders, files in os.walk(rootdir):
    for file in files:
        f = os.path.join(root,file)
        with open(f) as cf:
            [...]

但它非常非常慢。该进程已经运行了大约一个小时,仍然没有处理单个文件,但仍以每秒大约 2kB 的内存使用量增长。

【问题讨论】:

  • 是否可以选择重新构建文件系统,以便您拥有一堆文件夹,而不是一个包含大量文件的文件夹,每个文件夹都包含一些文件?
  • 是的,这是一个想法。但是在这里迭代和移动文件也需要很长时间?
  • 平面目录或目录树中的 1000000000 个文件?在后一种情况下,树有多深?
  • @SylvainLeroux 抱歉,它被过度编辑了......实际上它在平面目录中的 2.5m
  • 对于内存问题,尝试通过生成器交换“for file in files”(用于延迟评估):“ gen = (filex for filex in files); for file in gen: etc.”

标签: python windows


【解决方案1】:

我发现os.scandir(在 python 标准库中,自 3.5 起)似乎在 Windows 中也能做到这一点! (如 cmets 中所述,它在 MacOS 上同样出色地完成了它的工作)!

考虑以下示例:
“从包含数百万个文件的文件夹中检索 100 条路径”

os.scandir 在几分之一秒内实现了这一目标

import os
from itertools import islice
from pathlib import Path
path = Path("path to a folder with a lot of files")

paths = [i.path for i in islice(os.scandir(path), 100))]

所有其他经过测试的选项 (iterdir, glob, iglob) 不知何故花费了大量的时间,即使它们应该返回迭代器...

paths = list(islice(path.iterdir(), 100))
paths = list(islice(path.rglob(""), 100))
import glob
paths = list(islice(glob.iglob(str(path / "*.*")), 100))

【讨论】:

  • 也适用于 Mac。这为我节省了很多时间(等待列表)和痛苦:) 文件数量 1062996 并且还在增长......
【解决方案2】:

默认情况下os.walk 自下而上遍历目录树。如果你有一棵有很多叶子的深树,我这可能会导致性能损失——或者至少会增加“状态”时间,因为walk 必须在处理之前读取大量数据第一个文件。

所有这些都是推测性的,你是否试图强制进行自上而下的探索:

for root, subFolders, files in os.walk(rootdir, topdown=True):
    ...

编辑:

由于文件似乎位于平面目录中,glob.iglob 可能会通过返回迭代器来获得更好的性能(而其他方法如 os.walkos.listdirglob.glob 首先构建 列表 的所有文件)。你能试试这样的吗:

import glob

# ...
for infile in glob.iglob( os.path.join(rootdir, '*.*') ):
    # ...

【讨论】:

  • 我发现所有这些功能都那么糟糕,直到文件系统建立了它的索引文件。在Windows创建目录的b树之后(这是在您第一次迭代结构时完成的),一切都在几秒钟内启动。
  • 非常有趣。然而,基于glob.iglob 的答案有点令人失望。我对windows不是很熟悉,所以没必要很好理解。你是如何解决问题的?通过手动将您的“资源管理器”指向目录?还是在 Python 程序的第一次运行期间自动重建了索引?
  • 在这一点上似乎 windows 有点奇怪......当 B-Tree 没有建立起来时,你不会得到一个迭代器或类似的东西。如果有这样的树,您将立即收到迭代器并可以继续。但不知何故,在我移动了一些文件后,这棵树被删除了——这很奇怪,因为正如文档告诉我的那样,它应该被重建。如果它太大,也许它不会被重建......
  • 嗨@SylvainLeroux,你能看看这个问题stackoverflow.com/q/53719293/7644562好吗!
【解决方案3】:

我用过这样的东西:

from os import scandir
from os.path import isfile, join, exists
import os

def get_files(path):
    if exists(path):
        for file in scandir(path):
            full_path = join(path, file.name)
            if isfile(full_path):
                yield full_path
    else:
        print('Path doesn\'t exist')

def get_subdirs(path):
    if exists(path):
        for subdir in scandir(path):
            full_path = join(path, subdir.name)
            if not isfile(full_path):
                yield full_path
    else:
        print('Path doesn\'t exist')

def walk_dir(directory):
    yield from get_files(directory)
    for subdir in get_subdirs(directory):
        yield from walk_dir(subdir)

walk_dir 方法返回一个可用于遍历文件系统的生成器对象。在递归过程的任何步骤中,都不会创建目录列表,因此内存永远不会保存任何子目录中所有文件的列表。

【讨论】:

    猜你喜欢
    • 2017-04-03
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 2023-01-20
    • 2014-09-28
    • 2019-05-08
    相关资源
    最近更新 更多