我有一个包含90K文件的目录。这是一个非常庞大的文件,可以像bash一样使用 ls
失败。当然可以 os.listdir()
来自我的python(Mac Python,版本2.5)脚本;它失败了 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中取得成功。
你在Python中遇到了一个历史神器: os.listdir
应该返回一个迭代器,而不是一个数组。我认为这个函数早于迭代器 - 奇怪的是没有 os.xlistdir
已被添加。
这比在巨大的目录上使用内存更有效。即使在只有几千个文件的目录上,您也必须等待整个目录扫描完成,并且您必须阅读 整个 目录,即使第一个条目是您要查找的条目。
这在Python中是一个相当明显的缺点:似乎有 没有 绑定到低级别 opendir
/readdir
/fdopendir
API,所以看起来如果不编写本机模块就不可能自己实现它。这是标准库中如此庞大,空洞的漏洞之一,我怀疑自己并怀疑我只是没有看到它 - 有低级别 open
, stat
等等绑定,这属于同一类别。
您可以尝试更深入一级,并使用ctypes直接调用opendir()和readdir()。
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
列出一个大目录时,我在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在不应该的情况下随机失败“和”Posix的listdir()中的错误检查”。