Обходной путь OSError с os.listdir - PullRequest
11 голосов
/ 04 ноября 2010

У меня есть каталог с файлами 90K.Это настолько нелепо огромное количество файлов, что bash-функции, такие как ls, не работают.Так что, конечно, os.listdir() из моего скрипта python (Mac Python, версия 2.5);с ошибкой OSError: [Errno 12] Cannot allocate memory: '.'

Люди скажут: «Не кладите столько файлов в один каталог! Вы с ума сошли?»- но мне нравится притворяться, что я живу в будущем, блестящем, светящемся месте, где у меня есть гигабайты памяти, и мне не нужно слишком беспокоиться о том, куда именно отправляются мои файлы, пока естьржавчина осталась на моих вращающихся тарелках.

Итак, есть ли хороший обходной путь для этой os.listdir() проблемы?Я рассмотрел только обнуление до find, но это немного грубо, и, к сожалению, find является рекурсивным, без поддерживаемой опции maxdepth в Mac OS X 10.6.

Вот как выглядит файл 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

Обновление: os.listdir() преуспевает в Python 2.6.

Ответы [ 4 ]

7 голосов
/ 04 ноября 2010

Вы попали в исторический артефакт в Python: os.listdir должен возвращать итератор, а не массив. Я думаю, что эта функция предшествует итераторам - странно, что os.xlistdir не было добавлено.

Это имеет больше эффектов, чем просто использование памяти в огромных каталогах. Даже для каталога, содержащего всего несколько тысяч файлов, вам придется ждать завершения сканирования всего каталога и читать каталог весь , даже если первая запись Вы искали.

Это довольно явный недостаток в Python: нет привязки к низкоуровневым opendir / readdir / fdopendir API, поэтому кажется, что это даже невозможно реализовать это самостоятельно без написания собственного модуля. Это один из тех случаев, когда в стандартной библиотеке такая огромная зияющая дыра, что я сомневаюсь в себе и подозреваю, что просто ее не вижу - существуют низкоуровневые привязки open, stat и т. Д. и это в той же категории.

4 голосов
/ 04 ноября 2010

Вы можете попробовать перейти на один уровень глубже и напрямую вызвать opendir () и readdir (), используя ctypes.

2 голосов
/ 04 ноября 2010

Я получаю ту же ошибку IOEr на Apple Python 2.5.5 на 10.6 при выводе большого каталога.Это прекрасно работает в 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 случайным образом завершается ошибкой в ​​тех случаях, когда он не должен " и " Проверка неаккуратных ошибок в listdir () для Posix ".

2 голосов
/ 04 ноября 2010
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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...