使用os.listdir解决OSError问题

时间:2010-11-04 16:25:46

标签: python macos

我有一个包含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中取得成功。

4 个答案:

答案 0 :(得分:7)

你在Python中遇到了一个历史工件:os.listdir应该返回一个迭代器,而不是一个数组。我认为这个函数早于迭代器 - 奇怪的是没有添加os.xlistdir

这比大型目录上的内存使用效果更多。即使在只有几千个文件的目录上,您也必须等待整个目录扫描完成,并且您必须阅读整个目录,即使第一个条目是你要找的那个。

这是Python中非常明显的缺点:似乎没有绑定到低级opendir / readdir / fdopendir API,所以在没有编写本机模块的情况下,似乎甚至无法实现这一点。这是标准库中如此庞大,空洞的漏洞之一,我怀疑自己并怀疑我只是没有看到它 - 有低级openstat,等绑定,这属于同一类别。

答案 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”。