ОС.прогулка каталоге


Я использую этот скрипт, чтобы получить список всех моих фотографий в папке и ее подпапках. Однако, программа, кажется, очень медленно.

Есть 50,000 .картины JPG в этой папке и подпапках. Я могу уменьшить for петли, но программа все еще работает более или менее с той же скоростью.

Я открыт, чтобы, используя лямбда, но хотелось бы использовать базовые функции Python на максимальную скорость. Может кто-нибудь предложить улучшение?

import os
from fnmatch import fnmatch
import sys

root = "C:\\Users\\Agartha\\Desktop\\photos"
pattern = "*.jpg"

with open("./files\\list.txt", "w") as a:
    for path, subdirs, files in os.walk(root):
       for filename in files:
            if fnmatch(filename,pattern):
                a.write(str(os.path.join(filename)) + '\n')


Комментарии
3 ответа

Вот вам делать 4 вещи одновременно. Вы находитесь


  1. Гуляя по всем файлам каталога

  2. Сравнивая именем шаблону

  3. Форматирование именем

  4. Добавление имени файла

Чтобы выяснить, чем медленнее шаг, вы должны отделить этот

def find_files(root):
for path, subdirs, files in os.walk(root):
for filename in files:
yield filename

def filter_filename(files, pattern):
for filename in files:
if fnmatch(filename,pattern):
yield filename

def format_filenames(files, root):
for filename in files:
yield str(os.path.join(filename)) + '\n'

def writelines(out_file, files):
for filename in files:
out_file.write(filename)
# or:
# out_file.writelines(files)

def main(root, pattern, filename_out):
files = find_files(root)
files_filtered = filter_filename(files, pattern)
files_formatted = format_filenames(files, root)
with open(filename_out, 'w') as out_file:
writelines(out_file, files_formatted)

Потом, есть 4 вещи, которые вы можете время по отдельности, чтобы выяснить, самый большой преступник в момент потребления и поработать над этим:


  1. files = list(find_files(root))

  2. files_filtered = list(filter_filename(files, pattern))

  3. files_formatted = list(format_filenames(files, root))

  4. with open(filename_out, 'w') as out_file: writelines(out_file, files_formatted)

2
ответ дан 12 марта 2018 в 12:03 Источник Поделиться

Основная проблема заключается в том, что ваш метод в значительной степени опирается на свой жесткий диск. Этот процесс должен рекурсивно искать внутри каждого суб-папки, которые требуется время, особенно с 50000 файлов.

Поиска Windows гораздо быстрее, потому что он индексирует файлы и не сканировать весь диск для каждого запроса.

При использовании Питон3 возможность, единственное, что я бы изменил в вашем коде заключается в использовании glob и заменить петли:

import glob
glob.glob("C:\\Users\\Agartha\\Desktop\\photos\\**\\*.jpg", recursive=True)

2
ответ дан 12 марта 2018 в 01:03 Источник Поделиться

Для стартера, вы можете организовать код в виде функции и использовать if __name__ == '__main__' охранник.

Вы могли бы также изменить конструкцию for петли + if fnmatch.fnmatch в for … in fnmatch.filter().

Это дало бы что-то вроде:

import os
import fnmatch

def filter_files(path='~/Desktop', filter_pattern='*.jpg'):
for root, _, filenames in os.walk(os.path.expanduser(path)):
for filename in fnmatch.filter(filenames, filter_pattern):
yield os.path.join(root, filename)

def write_to_file(iterable, filename='files/list.txt'):
with open(filename, 'w') as output:
for element in iterable:
output.write(element)
output.write('\n')

if __name__ == '__main__':
pictures = filter_files('~/Desktop/photos')
write_to_file(pictures)

Однако, этот код может быть значительно улучшена, если вы переключитесь на использование Python 3.5+ как рекурсивная фильтрация точно реализованы в glob.glob:

import glob

def write_to_file(iterable, filename='files/list.txt'):
with open(filename, 'w') as output:
for element in iterable:
output.write(element)
output.write('\n')

if __name__ == '__main__':
pattern = 'C:\\Users\\Agartha\\Desktop\\photos\\**\\*.jpg'
pictures = glob.iglob(pattern, recursive=True)
write_to_file(pictures)

Еще можно сохранить filter_files функции для упрощения интерфейса:

import glob
from os.path import expanduser, join as path_join

def filter_files(path='~/Desktop', filter_pattern='*.jpg'):
pattern = path_join(expanduser(path), '**', filter_pattern)
yield from glob.iglob(pattern, recursive=True)

def write_to_file(iterable, filename='files/list.txt'):
with open(filename, 'w') as output:
for element in iterable:
output.write(element)
output.write('\n')

if __name__ == '__main__':
pictures = filter_files('~/Desktop/photos')
write_to_file(pictures)

2
ответ дан 12 марта 2018 в 01:03 Источник Поделиться