解决os.listdir中的OSError问题
我有一个文件夹,里面有9万个文件。这真是个超级庞大的数字,以至于像 ls
这样的命令都无法正常工作。我的Python脚本中的 os.listdir()
也失败了,报错信息是 OSError: [Errno 12] Cannot allocate memory: '.'
。
有人会说:“别把这么多文件放在一个文件夹里!你疯了吗?”——但我喜欢假装自己生活在未来,一个光辉灿烂的地方,那里有大量的内存可供我使用,我不需要太担心我的文件放在哪里,只要我的硬盘还有空间就行。
那么,有没有什么好的办法来解决这个 os.listdir()
的问题呢?我考虑过直接用 find
命令,但这有点麻烦,而且不幸的是,find
是递归的,在Mac OS X 10.6上没有支持的最大深度选项。
下面是通过调用 find
来实现的 os.listdir()
的大致样子:
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
更新: 在Python 2.6中,os.listdir()
可以正常工作。
4 个回答
你可以试着更深入一步,直接使用ctypes来调用opendir()和readdir()这两个函数。
你遇到了Python中的一个历史遗留问题:os.listdir
应该返回一个迭代器,而不是一个数组。我觉得这个函数是在迭代器出现之前就存在的——奇怪的是,居然没有添加os.xlistdir
这个函数。
这个问题不仅仅影响内存使用,尤其是在处理非常大的文件夹时。即使在一个只有几千个文件的文件夹里,你也得等整个文件夹的扫描完成,甚至需要读取所有的文件,即使你只想找第一个文件。
这在Python中是个明显的缺陷:似乎没有与低级的opendir
/readdir
/fdopendir
这些API的绑定,所以看起来你甚至无法自己实现这个功能,除非写一个本地模块。这种情况就像是标准库中有个巨大的漏洞,让我怀疑自己是不是没看清楚——虽然有低级的open
、stat
等绑定,但这个问题也应该属于同一类。
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
当然可以!请把你想要翻译的内容发给我,我会帮你把它变得更简单易懂。