Подтвердить что ты не робот

Обходной путь OSError с os.listdir

У меня есть каталог с 90K файлами. Это такое невероятно огромное количество файлов, которые bash функционируют как ls сбой. Так что, конечно, os.listdir() из моего python (Mac Python, версия 2.5) script; он терпит неудачу с 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.

4b9b3361

Ответ 1

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

Ответ 2

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

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

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

Ответ 3

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

Ответ 4

Я получаю тот же IOError на 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".