2015-11-18 1 views
0

Python 2.7.5 Win/Mac.Как оптимизировать поиск с помощью списка dir и path walk?

Я пытаюсь найти лучший способ поиска файлов (более 10000) на нескольких хранилищах (около 128Tio). Эти файлы имеют определенные расширения, и я могу игнорировать некоторые папки.

Вот моя первая функция os.listdir и рекурсии:

count = 0 
def SearchFiles1(path): 
    global count 
    pathList = os.listdir(path) 
    for i in pathList: 
     subPath = path+os.path.sep+i 
     if os.path.isfile(subPath) == True : 
      fileName = os.path.basename(subPath) 
      extension = fileName[fileName.rfind("."):] 
      if ".ext1" in extension or ".ext2" in extension or ".ext3" in extension: 
       count += 1 
       #do stuff . . . 
     else : 
      if os.path.isdir(subPath) == True: 
       if not "UselessFolder1" in subPath and not "UselessFolder1" in subPath: 
        SearchFiles1(subPath) 

Это работает, но я думаю, что это могло бы быть лучше (быстрее и собственно) или я не прав?

Так что я попытался os.path.walk:

def SearchFiles2(path): 
    count = 0 
    for dirpath, subdirs, files in os.walk(path): 
     for i in dirpath: 
      if not "UselessFolder1" in i and not "UselessFolder1" in i: 
       for y in files: 
        fileName = os.path.basename(y) 
        extension = fileName[fileName.rfind("."):] 
        if ".ext2" in extension or ".ext2" in extension or ".ext3" in extension: 
         count += 1 
         # do stuff . . . 
    return count 

"счетчик" не так и способ медленнее. И я думаю, что я действительно не понимаю, как работает path.walk.

Мой вопрос: что я могу сделать для оптимизации этого исследования?

ответ

1

Ваше первое решение разумно, за исключением того, что вы можете использовать os.path.splitext. Во втором решении это неверно, потому что вы пересматриваете список файлов для каждого поддиректа, а не просто обрабатываете его один раз. С os.path.walk фокус в том, что каталоги, удаленные с subdirs, не являются частью следующего раунда перечислений.

def SearchFiles2(path): 
    useless_dirs = set(("UselessFolder1", "UselessFolder2")) 
    useless_files = set((".ext1", ".ext2")) 
    count = 0 
    for dirpath, subdirs, files in os.walk(path): 
     # remove unwanted subdirs from future enumeration 
     for name in set(subdirs) & useless_dir: 
      subdirs.remove(name) 
     # list of interesting files 
     myfiles = [os.path.join(dirpath, name) for name in files 
      if os.path.splitext(name)[1] not in useless_files] 
     count += len(myfiles) 
     for filepath in myfiles: 
      # example shows file stats 
      print(filepath, os.stat(filepath) 
    return count 

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

+0

Благодаря вашему примеру я улучшил первое решение (os.path.splitext и сравните строку с кортежем содержимого). Это немного быстрее, и мы можем легко добавить дополнительные правила (файл ext/ignore subdir). – Syrius

+0

Для второго решения мне не удалось заставить его работать. Сначала я предполагаю, что это «бесполезные_диры» в строке 7, но я получил ошибку: «ValueError: list.remove (x): x not in list». Я добавил «имя печати» и увидел, что он пытается удалить бесполезные_dirs [x] из поддиректоров, даже если он не существует. – Syrius

+0

@Syrius Мой плохой ... Я использовал 'и', когда я должен был использовать '&'. – tdelaney

0

Таким образом, после испытаний и обсуждения с tdelaney я оптимизировал оба решения следующим образом:

import os 

count = 0 
target_files = set((".ext1", ".ext2", ".ext3")) # etc 
useless_dirs = set(("UselessFolder2", "UselessFolder2")) # etc 
# it could be target_dirs, just change `in` with `not in` when compared. 

def SearchFiles1(path): 
    global count 
    pathList = os.listdir(path) 
    for content in pathList: 
     fullPath = os.path.join(path,content) 
     if os.path.isfile(fullPath): 
      if os.path.splitext(fullPath)[1] in target_files: 
       count += 1 
       #do stuff with 'fullPath' . . . 
     else : 
      if os.path.isdir(fullPath): 
       if fullPath not in useless_dirs: 
        SearchFiles1(fullPath) 

def SearchFiles2(path): 
    count = 0 
    for dirpath, subdirs, files in os.walk(path): 
     for name in set(subdirs) & useless_dirs: 
      subdirs.remove(name) 
     for filename in [name for name in files if os.path.splitext(name)[1] in target_files]: 
      count += 1 
      fullPath = os.path.join(dirpath, filename) 
      #do stuff with 'fullPath' . . . 
    return count 

Он отлично работает на Mac/PC v2.7.5

О скорости это полностью даже.