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

Python 有没有一种方法可以有效地生成包含数百万个文件的目录中的每个文件?,python,list,file,yield,Python,List,File,Yield,我知道os.listdir,但据我所知,它将目录中的所有文件名都存储到内存中,然后返回列表。我想要的是一种生成文件名的方法,处理它,然后生成下一个文件名,而无需将它们全部读入内存 有没有办法做到这一点?我担心使用这种方法更改文件名、添加新文件和删除文件的情况。某些迭代器阻止您在迭代过程中修改集合,主要是通过在开始时拍摄集合状态的快照,并在每个move操作中比较该状态。如果存在能够从路径生成文件名的迭代器,那么如果存在修改集合的文件系统更改(添加、删除、重命名迭代目录中的文件),是否会引发错误 可

我知道
os.listdir
,但据我所知,它将目录中的所有文件名都存储到内存中,然后返回列表。我想要的是一种生成文件名的方法,处理它,然后生成下一个文件名,而无需将它们全部读入内存

有没有办法做到这一点?我担心使用这种方法更改文件名、添加新文件和删除文件的情况。某些迭代器阻止您在迭代过程中修改集合,主要是通过在开始时拍摄集合状态的快照,并在每个
move
操作中比较该状态。如果存在能够从路径生成文件名的迭代器,那么如果存在修改集合的文件系统更改(添加、删除、重命名迭代目录中的文件),是否会引发错误

可能有一些情况会导致迭代器失败,这完全取决于迭代器如何维护状态。以S.Lotts为例:

filea.txt
fileb.txt
filec.txt
迭代器生成
filea.txt
。在
处理过程中
filea.txt
被重命名为
filey.txt
fileb.txt
被重命名为
filez.txt
。当迭代器尝试获取下一个文件时,如果它使用文件名
filea.txt
查找它的当前位置以查找下一个文件,而
filea.txt
不存在,会发生什么情况?它可能无法恢复其在集合中的位置。类似地,如果迭代器在生成
filea.txt
时获取
fileb.txt
,它可能会查找
fileb.txt
的位置,失败并产生错误

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

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

编辑:

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

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

编辑:

有效期的定义:

形容词 1.有根据的或正当的、中肯的

(对不起,S.洛特,我无法抗拒)


我已经编辑了上面讨论的段落。

从2.5版开始的glob模块Python有一个iglob方法,它返回一个迭代器。 迭代器正是为了不在内存中存储巨大的值

glob.iglob(pathname)
Return an iterator which yields the same values as glob() without
actually storing them all simultaneously.
例如:

import glob
for eachfile in glob.iglob('*'):
    # act upon eachfile
我想要的是一种生成文件名的方法,处理它,然后生成下一个文件名,而无需将它们全部读入内存

任何方法都不会显示“已更改”的文件名。甚至不清楚你所说的“文件名更改、添加新文件和删除文件”是什么意思?您的用例是什么

假设您有三个文件:
a.a
b.b
c.c

您神奇的“迭代器”以
a.a
开头。你来处理它

神奇的“迭代器”移动到
b.b
。你正在处理它

同时将
a.a
复制到
a1.a1
,删除
a.a
。现在怎么办?你的神奇迭代器用这些做什么?它已通过
a.a
。因为
a1.a1
b.b
之前,所以它永远不会看到它。“更改文件名、添加新文件和删除文件”会发生什么情况

神奇的“迭代器”移动到
c.c
。其他文件应该怎么办?你怎么知道删除的事


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

不要使用裸文件系统进行协调

使用队列

进程A写入文件并将添加/更改/删除memento排入队列


进程B从队列中读取memento,然后对memento中命名的文件进行后续处理。

我认为由于文件IO的性质,您所要求的是不可能的。一旦python检索到目录列表,它就无法在磁盘上维护实际目录的视图,python也无法坚持让操作系统通知它对目录的任何修改

python所能做的就是要求定期列出清单,并区分结果,以查看是否有任何更改

最好是在目录中创建一个信号量文件,让其他进程知道python进程希望没有其他进程修改目录。当然,只有当您将信号量显式编程为时,它们才会观察信号量。

tl;dr:从Python3.5(目前处于测试版)开始,只需使用
os.scandir

正如我在前面所写的,由于“iglob”只是一个真正迭代器的门面,所以您必须调用低级系统函数,以便一次获得一个您想要的函数。幸运的是,从Python调用低级函数是可行的。 Windows和Posix/Linux系统的低级功能不同

  • 如果您在Windows上,您应该检查
    win32api
    是否有任何读取“目录中的下一个条目”的调用,或者如何执行其他操作
  • 如果您使用的是Posix/Linux,则可以直接通过ctypes调用libc函数,每次获得一个文件目录条目(包括命名信息)。#!/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