有没有一种方法可以有效地生成包含数百万个文件的目录中的每个文件?

2024-04-05

我知道os.listdir,但据我所知,它将目录中的所有文件名放入内存,然后返回列表。我想要的是一种生成文件名、对其进行处理,然后生成下一个文件名的方法,而不会将它们全部读入内存。

有什么办法可以做到这一点吗?我担心使用这种方法更改文件名、添加新文件以及删除文件的情况。有些迭代器会阻止您在迭代期间修改集合,本质上是通过在开始时拍摄集合状态的快照,然后比较每个迭代器的状态move手术。如果有一个迭代器能够从路径生成文件名,那么如果存在修改集合的文件系统更改(在迭代目录中添加、删除、重命名文件),它是否会引发错误?

在某些情况下可能会导致迭代器失败,这完全取决于迭代器如何维护状态。使用 S.Lotts 示例:

filea.txt
fileb.txt
filec.txt

迭代器产量filea.txt。期间processing, filea.txt被重命名为filey.txt and fileb.txt被重命名为filez.txt。当迭代器尝试获取下一个文件时,如果要使用文件名filea.txt找到它的当前位置以便找到下一个文件filea.txt不存在的话会发生什么?它可能无法恢复其在集合中的位置。类似地,如果迭代器要获取fileb.txt当屈服时filea.txt,它可以查找的位置fileb.txt,失败并产生错误。

如果迭代器能够以某种方式维护索引dir.get_file(0),那么维护位置状态不会受到影响,但某些文件可能会丢失,因为它们的索引可能会移动到迭代器“后面”的索引。

当然,这都是理论上的,因为似乎没有内置(python)方法来迭代目录中的文件。不过,下面有一些很好的答案,可以通过使用队列和通知来解决问题。

Edit:

值得关注的操作系统是 Redhat。我的用例是这样的:

进程A不断地将文件写入存储位置。 进程 B(我正在编写的进程)将迭代这些文件,根据文件名进行一些处理,并将文件移动到另一个位置。

Edit:

有效的定义:

形容词 1. 有充分依据或合理、相关。

(对不起,S.Lott,我无法抗拒)。

我已经编辑了上面有问题的段落。


tl;博士:从 Python 3.5(目前处于测试版)开始,只需使用os.scandir更新>

正如我之前所写,由于“iglob”只是真正迭代器的一个外观,因此您必须调用低级系统函数才能像您想要的那样一次获取一个迭代器。幸运的是,可以从 Python 调用低级函数。 Windows 和 Posix/Linux 系统的低级函数是不同的。

  • 如果您使用的是 Windows,您应该检查是否win32api有任何调用来读取“目录中的下一个条目”或如何继续。
  • 如果您使用的是 Posix/Linux,则可以直接通过 ctypes 调用 libc 函数并一次获取文件目录条目(包括命名信息)。

关于 C 函数的文档在这里:http://www.gnu.org/s/libc/manual/html_node/Opening-a-Directory.html#Opening-a-Directory http://www.gnu.org/s/libc/manual/html_node/Opening-a-Directory.html#Opening-a-Directory

http://www.gnu.org/s/libc/manual/html_node/Reading_002fClosing-Directory.html#Reading_002fClosing-Directory http://www.gnu.org/s/libc/manual/html_node/Reading_002fClosing-Directory.html#Reading_002fClosing-Directory

我提供了一段 Python 代码,演示了如何调用低级 C 函数在我的系统上但此代码片段可能不适用于您的系统[footnote-1]。我建议打开你的/usr/include/dirent.h头文件并验证 Python 代码片段是否正确(您的 PythonStructure必须匹配Cstruct)在使用代码片段之前。

这是使用的片段ctypes and libc我已经将它们放在一起,允许您获取每个文件名并对其执行操作。注意ctypes当你这样做时,会自动给你一个Python字符串str(...)在结构体上定义的 char 数组上。 (我正在使用print语句,它隐式调用Python的str)

#!/usr/bin/env python2
from ctypes import *

libc = cdll.LoadLibrary( "libc.so.6")
dir_ = c_voidp( libc.opendir("/home/jsbueno"))

class Dirent(Structure):
    _fields_ = [("d_ino",  c_voidp),
                ("off_t", c_int64),
                ("d_reclen", c_ushort),
                ("d_type", c_ubyte),
                ("d_name", c_char * 2048)
            ]

while True:
    p  = libc.readdir64(dir_)
    if not p:
        break
    entry = Dirent.from_address( p)
    print entry.d_name

update:Python 3.5 现在处于测试阶段 - Python 3.5 中的新版本os.scandir函数调用可作为具体化使用PEP 471 https://www.python.org/dev/peps/pep-0471/(“更好更快的目录迭代器”)它完全符合这里的要求,此外还有许多其他优化,可以将速度提高多达 9 倍os.listdirWindows 下的大型目录列表(Posix 系统中增加 2-3 倍)。

[脚注-1]dirent64 C struct在每个系统的 C 编译时确定。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有没有一种方法可以有效地生成包含数百万个文件的目录中的每个文件? 的相关文章

随机推荐