2016-03-01 8 views
0

Я пытаюсь найти все файлы .xlsm (и получить их статистику) на сетевом диске O:\ при условии, что они не находятся в папке с именем, Test. Я использовал os.walk и переключился на scandir.walk, потому что он быстрее. Сейчас я просто ограничен скоростью сети. Этот код, похоже, имеет много взаимодействия между скриптом и сетевым диском. Мой код ниже. Есть ли способ ускорить это, возможно, используя пакетный файл? Я нахожусь в Windows.os.walk/scandir slow на сетевом диске

from scandir import scandir, walk 
import sys 

def subdirs(path): 
    for path, folders, files in walk(path): 
     if 'Test' not in path: 
      for sub_files in scandir(path): 
       if '.xlsm' in sub_files.path: 
        yield subfiles.stat() 

for i in subdirs('O:\\'): 
    print i 

ответ

3

Вы дважды сканируя каждый путь, когда-то неявно с помощью walk, затем снова явно повторно scandir тами pathwalk вернулся без причины. walk уже вернул files, так что внутренний контур может избежать двойного сканирования, используя только то, что оно было дано:

def subdirs(path): 
    for path, folders, files in walk(path): 
     for file in files: 
      if '.xlsm' in file: 
       yield os.path.join(path, file) 

Для решения обновленного вопроса, вы, вероятно, хотите или скопировать существующий scandir.walk код и изменить он должен вернуть list s из DirEntry s вместо list с именами или написать аналогичный специальный код с обложкой для ваших нужд; в любом случае это позволит избежать двойного сканирования, сохраняя при этом низкое накладное поведение scandir. Например:

def scanwalk(path, followlinks=False): 
    '''Simplified scandir.walk; yields lists of DirEntries instead of lists of str''' 
    dirs, nondirs = [], [] 
    for entry in scandir.scandir(path): 
     if entry.is_dir(follow_symlinks=followlinks): 
      dirs.append(entry) 
     else: 
      nondirs.append(entry) 
    yield path, dirs, nondirs 
    for dir in dirs: 
     for res in scanwalk(dir.path, followlinks=followlinks): 
      yield res 

Вы можете заменить использование walk с ним, как это (я также добавил код, чернослив каталоги с Test в них, так как все каталоги и файлы под ними были бы отвергнуты исходным кодом, но вы все еще пройти их без надобности):

def subdirs(path): 
    # Full prune if the path already contains Test 
    if 'Test' in path: 
     return 
    for path, folders, files in scanwalk(path): 
     # Remove any directory with Test to prevent traversal 
     folders[:] = [d for d in folders if 'Test' not in d.name] 
     for file in files: 
      if '.xlsm' in file.path: 
       yield file.stat() # Maybe just yield file to get raw DirEntry? 

for i in subdirs('O:\\'): 
    print i 

Кстати, вы можете перепроверить, что вы правильно установили/построил C ускоритель для scandir, _scandir. Если _scandir не построен, модуль scandir обеспечивает резервные реализации с использованием ctypes, но они значительно медленнее, что может объяснить проблемы с производительностью. Попробуйте запустить import _scandir в интерактивной сессии Python; если он поднимает ImportError, то у вас нет ускорителя, поэтому вы используете медленную резервную реализацию.

+0

Единственная проблема заключается в том, что я теряю другие переменные, связанные с файлами, которые мне обычно нужно получить через 'os.stat()' см: https://github.com/benhoyt/scandir – user2242044

+0

@ user2242044: Я знаю про «скандир» (я регулярно евангелизую его), но ваш исходный код был только «yield» по пути, а не к объекту «DirEntry»; вы не использовали бесплатное/кэшированное поведение 'stat'. Если вам нужна информация 'stat', вы можете скопировать реализацию' scandir.walk' и изменить ее, чтобы возвращать 'list' из исходных объектов 'DirEntry' для' dirnames' и 'filenames' вместо возврата' list' из 'str'. Это становится лучшим из обоих миров; однопроходное сканирование, не повторяющееся 'stat'ing. Или просто реализуйте свою собственную рекурсивную функцию, которая специализируется на вашем случае использования. – ShadowRanger

+0

@ ShadowRanger .. Спасибо за разъяснение. Я попытался упростить код для вопроса SO, но думаю, что я потерял некоторые намерения. Двойная итерация состояла в том, что я старался избегать повтора нескольких папок, и я хочу получить доход от статистики. Изменен исходный вопрос. Благодаря! – user2242044