在Python中从目录中随机选择一个文件(文件数量众多)
我有一个文件夹,里面有很多文件(大约有一百万个)。我需要从这个文件夹里随机选择一个文件。因为文件实在太多了,使用 os.listdir
方法会花费很长时间才能完成。
有没有什么办法可以解决这个问题?比如说,能不能不列出所有文件的情况下,先知道这个文件夹里有多少个文件,然后随机选择第 'n' 个文件,其中 n 是随机生成的?
文件夹里的文件名都是随机的。
5 个回答
我有一个和楼主类似的需求。
我想我会采用一种预缓存的方法:你可以把所有文件的列表存储在一个.txt文件里,然后你只需要聪明地随机选择一行(甚至不需要把整个文件加载到内存中),这样就搞定了!
当然,你还需要更新这个缓存,更重要的是要定义什么时候需要更新缓存,不过根据你的需求,这可能很简单(比如在特定操作后,或者当某些东西发生变化时等等)。
这是一个用Python编写的聪明读取文件中随机一行的代码,作者是Jonathan Kupferman:
http://www.regexprn.com/2008/11/read-random-line-in-large-file-in.html
我不太确定这是否可能。即使在虚拟文件系统(VFS)或文件系统层面,也没有保证会维护目录项的数量。比如,很多文件系统只是记录了一个目录中所有目录项结构的字节总大小。
如果目录项是固定大小的结构,可能可以进行估算,但这种情况现在并不常见(比如FAT32的长文件名)。即使某个文件系统确实提供了一个目录项的数量,而不需要逐个查看目录,或者如果虚拟文件系统缓存了目录的长度记录,这些都肯定是特定于操作系统、文件系统和内核的。
可惜,我觉得你的问题没有解决办法。首先,我不知道有什么通用的API可以直接告诉你目录里有多少个条目,而不需要先列出它们。其次,我也不认为有API可以通过编号而不是名字来返回目录条目。
所以,总的来说,程序必须遍历目录里的所有条目,才能随机选出一个。简单的方法是先确定条目的数量,然后再随机挑一个,但这样要么需要足够的内存来存放完整的列表(os.listdir()
),要么就得再遍历一次目录来找到随机的那个条目——平均来说,这样的操作次数是n+n/2
。
有一种稍微好一点的方法,但也只是稍微好一点——你可以看看从文件中随机选择行。简单来说,有一种方法可以在不知道列表长度的情况下,从列表或迭代器中随机选取条目,同时每次只读取一个条目,并确保每个条目被选中的概率是相等的。但这对os.listdir()
没有帮助,因为它已经在内存中返回了一个包含所有100万+条目的list
——所以你也可以直接问它len()
的结果……