我有一个包含90K文件的目录。这是一个非常大量的文件,像ls
这样的bash函数失败了。当然,我的python(Mac Python,2.5版)脚本中有os.listdir()
;它以OSError: [Errno 12] Cannot allocate memory: '.'
人们会说“不要把那么多文件放在一个目录里!你疯了吗?” - 但我喜欢假装我生活在未来,一个辉煌,发光的地方,我可以随意使用千兆字节的内存,而且不需要太担心我的文件到底在哪里,只要有我的旋转盘片上留下了锈迹。
那么,这个os.listdir()
问题有一个很好的解决方法吗?我认为只是炮轰find
,但这有点严重,不幸的是find
是递归的,Mac OS X 10.6上没有受支持的maxdepth选项。
这是os.listdir通过shell来查找的内容,粗略地说:
def ls(directory):
import os
files = os.popen4('find %s' % directory)[1].read().rstrip().split('\n')
files.remove(directory)
return files # probably want to remove dir prefix from everything in here too
更新: os.listdir()
在python 2.6中取得成功。
答案 0 :(得分:7)
你在Python中遇到了一个历史工件:os.listdir
应该返回一个迭代器,而不是一个数组。我认为这个函数早于迭代器 - 奇怪的是没有添加os.xlistdir
。
这比大型目录上的内存使用效果更多。即使在只有几千个文件的目录上,您也必须等待整个目录扫描完成,并且您必须阅读整个目录,即使第一个条目是你要找的那个。
这是Python中非常明显的缺点:似乎没有绑定到低级opendir
/ readdir
/ fdopendir
API,所以在没有编写本机模块的情况下,似乎甚至无法实现这一点。这是标准库中如此庞大,空洞的漏洞之一,我怀疑自己并怀疑我只是没有看到它 - 有低级open
,stat
,等绑定,这属于同一类别。
答案 1 :(得分:4)
您可以尝试更深入一级,并使用ctypes直接调用opendir()和readdir()。
答案 2 :(得分:2)
def ls(directory):
"""full-featured solution, via wrapping find"""
import os
files = os.popen4('find %s' % directory)[1].read().rstrip().split('\n')
files.remove(directory)
n = len(directory)
if directory[-1] != os.path.sep:
n += 1
files = [f[n:] for f in files] # remove dir prefix
return [f for f in files if os.path.sep not in f] # remove files in sub-directories
答案 3 :(得分:2)
在列出大目录时,我在10.6上的Apple Python 2.5.5上得到了相同的IOError。它在Python2.6中运行得很好。
Python 2.5.5 (r255:77872, Sep 21 2010, 09:52:31)
[GCC 4.2.1 (Apple Inc. build 5664)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> x = os.listdir('.')
OSError: [Errno 12] Cannot allocate memory: '.'
这似乎是Python2.5中的一个错误。请参阅“os.listdir randomly fails on occasions when it shouldn't”和“Sloppy error checking in listdir() for Posix”。