Переопределение os.walk для возврата объекта генератора в качестве третьего элемента

Проверяя эффективность os.walk, я создал 6,00,000 файлов со строкой Hello <number> (где число — это просто число, обозначающее номер файла в каталоге), например содержимое файлов в каталоге будет выглядеть так: -

File Name | Contents
1.txt     | Hello 1
2.txt     | Hello 2
.
.
600000.txt|Hello 600000

Теперь я запустил следующий код: -

a= os.walk(os.path.join(os.getcwd(),'too_many_same_type_files')) ## Here, I am just passing the actual path where those 6,00,000 txt files are present
print a.next()

Проблема, которую я чувствовал, заключалась в том, что a.next() занимает слишком много времени и памяти, потому что третий элемент, который a.next() вернет, — это список файлов в каталоге (в котором 600000 элементов). Итак, я пытаюсь найти способ уменьшить сложность пространства (по крайней мере), каким-то образом заставив a.next() возвращать объект генератора в качестве третьего элемента кортежа вместо списка имен файлов.

Будет ли это хорошей идеей, чтобы уменьшить сложность пространства?


person GodMan    schedule 16.08.2012    source источник
comment
Плохая идея иметь 600 000 файлов в одном каталоге, потому что это серьезно ухудшит производительность файловой системы. И даже если вы это сделаете, хранение 600 000 имен файлов в памяти обычно занимает около 20 МБ места. Эти 20 МБ, безусловно, не самый плохой эффект от наличия такого количества файлов в одном каталоге. Я рекомендую устранить настоящую проблему.   -  person Sven Marnach    schedule 16.08.2012
comment
Я почти уверен, что это зависит от используемой файловой системы   -  person Useless    schedule 16.08.2012
comment
На самом деле невозможно вернуть генератор имен файлов из-за того, как операционная система возвращает файлы...   -  person Wayne Werner    schedule 16.08.2012
comment
@WayneWerner: по крайней мере, в Linux readdir() дает вам записи каталога одну за другой, и я помню, как это работало и в DOS. А вот про Windows не знаю...   -  person Sven Marnach    schedule 16.08.2012
comment
@Useless: почти каждая широко используемая файловая система работает медленно из-за слишком большого количества файлов в одном каталоге. Если я правильно помню, XFS является исключением из этого правила, но шансы, что OP использует XFS, ничтожны.   -  person Sven Marnach    schedule 16.08.2012


Ответы (3)


Как уже упоминалось, 600 000 файлов в каталоге — плохая идея. Изначально я думал, что реально никак это сделать из-за того, как вы получаете доступ к списку файлов, но оказывается, что я ошибаюсь. Вы можете использовать следующие шаги для достижения желаемого:

  1. Используйте подпроцесс или os.system для вызова ls или dir (в зависимости от того, на какой ОС вы работаете). Направьте вывод этой команды во временный файл (скажем, /tmp/myfiles или что-то в этом роде. В Python есть модуль, который может вернуть вам новый файл tmp).

  2. Откройте этот файл для чтения в Python.

  3. Файловые объекты повторяемы и будут возвращать каждую строку, так что пока у вас есть только имена файлов, все будет в порядке.

person Wayne Werner    schedule 16.08.2012

Это такая хорошая идея, так работает лежащий в основе C API!

Если вы можете получить доступ к readdir, вы можете это сделать: к сожалению, это не так. непосредственно выставленный Python.

Этот вопрос показывает два подхода (оба с недостатками).

Более чистым подходом было бы написать модуль на C, чтобы предоставить желаемую функциональность.

person Useless    schedule 16.08.2012
comment
Я не смотрел на другой вопрос, но в Python вы можете использовать glob.iglob("*") и glob.iglob(".*"), например, итератор для всех записей каталога. Я не вижу серьезных недостатков в этом подходе. - person Sven Marnach; 16.08.2012

os.walk вызывает listdir() под капот для извлечения содержимого корневого каталога затем переходит к разделению возвращенного списка элементов на каталоги и не каталоги.

Чтобы достичь того, чего вы хотите, вам нужно копнуть намного ниже и реализовать не только свою собственную версию walk(), но и альтернатива listdir(), которая возвращает генератор. Обратите внимание, что даже в этом случае вы не сможете предоставить независимые генераторы как для каталогов, так и для файлов, если вы не сделаете два отдельных вызова модифицированногоlistdir() и не отфильтруете результаты на лету.

Как предложил Свен в комментариях выше, возможно, было бы лучше решить реальную проблему (слишком много файлов в каталоге), а не перепроектировать решение.

person Shawn Chin    schedule 16.08.2012