Python OS.WALK Удалить каталоги

Я пытаюсь удалить каталоги из os.walk (мне не нужны файлы из этих каталогов)

Мой код:

def findit(root, exclude_files=[], exclude_dirs=[]):
    exclude_files = (fnmatch.translate(i) for i in exclude_files)
    exclude_files = '('+')|('.join(exclude_files)+')'
    exclude_files = re.compile(exclude_files)
    exclude_dirs = (os.path.normpath(i) for i in exclude_dirs)
    exclude_dirs = (os.path.normcase(i) for i in exclude_dirs)
    exclude_dirs = set(exclude_dirs)
    return (os.path.join(r,f)
           for r,_,f in os.walk(root)
           if os.path.normpath(os.path.normcase(r)) not in exclude_dirs
           for f in f
           if not exclude_files.match(os.path.normcase(f)))

Он работает, фильтруя файлы, когда я пытаюсь отфильтровать c:/windows, он все равно будет показывать мои файлы из каталогов Windows, я что-то упустил?

   filelist = list(findit('c:/',exclude_files = ['*.dll', '*.dat', '*.log', '*.exe'], exclude_dirs = ['c:/windows', 'c:/program files', 'c:/else']))

person Community    schedule 01.08.2014    source источник
comment
Мои извинения, пропустил, что вы возвращали выражение генератора.   -  person Martijn Pieters    schedule 01.08.2014


Ответы (3)


При фильтрации каталогов вы не предотвращаете доступ os.walk() к подкаталогам.

Для этого вам нужно очистить список dirs:

def findit(root, exclude_files=[], exclude_dirs=[]):
    exclude_files = (fnmatch.translate(i) for i in exclude_files)
    exclude_files = '('+')|('.join(exclude_files)+')'
    exclude_files = re.compile(exclude_files)
    exclude_dirs = (os.path.normpath(i) for i in exclude_dirs)
    exclude_dirs = (os.path.normcase(i) for i in exclude_dirs)
    exclude_dirs = set(exclude_dirs)
    for current, dirs, files in os.walk(root):
        if os.path.normpath(os.path.normcase(current)) in exclude_dirs:
            # exclude this dir and subdirectories
            dirs[:] = []
            continue
        for f in files:
            if not exclude_files.match(os.path.normcase(f)):
                yield os.path.join(current, f)

Присваивание dirs[:] = [] очищает список на месте; он удаляет все имена каталогов из списка. Поскольку этот список используется совместно с os.walk(), и последний использует этот список для последующего посещения подкаталогов, это эффективно предотвращает посещение этих подкаталогов os.walk().

person Martijn Pieters    schedule 01.08.2014

Прочитав ответ выше, я задумался. Мне показалось, что os.walk отсутствовал, а корневой параметр, похоже, не использовался по мере необходимости. Кроме того, должен работать случай, когда любой из необязательных аргументов является пустым списком. Предлагая небольшое изменение с меньшим поиском пространства имен и исключением подстановочных знаков для каталогов на каждом уровне каталога:

import os
import re
import fnmatch
import os.path


def findit(root, exclude_files=[], exclude_dirs=[], exclude_dirs_wc=[]):
    """Generate all files found under root excluding some.

    Excluded files are given as a list of Unix shell-style wildcards
    that exclude matches in each directory.  Excluded directories are
    assumed to be paths starting at root; no wildcards.  Directory
    wildcards at each level can be supplied.

    """
    # Less namespace look-up.
    join = os.path.join
    normpath = os.path.normpath; normcase = os.path.normcase
    #
    def make_exclude_regex_from(lst):
        if len(lst):
            lst = (fnmatch.translate(i) for i in lst)
            lst = "({})".format(")|(".join(lst))
            lst = re.compile(lst)
        return lst
    #
    exclude_files = make_exclude_regex_from(exclude_files)
    exclude_dirs_wc = make_exclude_regex_from(exclude_dirs_wc)
    if len(exclude_dirs):
        exclude_dirs = (normpath(i) for i in exclude_dirs)
        exclude_dirs = (normcase(i) for i in exclude_dirs)
        exclude_dirs = set(exclude_dirs)
    for current, dirs, files in os.walk(root):
        current_dir = normpath(normcase(current))
        if exclude_dirs and current_dir in exclude_dirs:
            # Prune set of dirs to exclude.
            exclude_dirs.discard(current_dir)
            # Disregard sub-directories.
            dirs[:] = []  # IN PLACE, since it is a loop var.
            continue
        if exclude_dirs_wc:
            for dd in dirs[:]:
                if exclude_dirs_wc.match(normcase(dd)):
                    dirs.remove(dd)  # IN PLACE
        if exclude_files:
            for ff in files[:]:
                if exclude_files.match(normcase(ff)):
                    files.remove(ff)  # IN PLACE; also a loop var.
        for f in files:
            yield join(current,f)
person FredrikHedman    schedule 01.08.2014
comment
да, я заметил, что os.walk отсутствует. Я исправил это сам, и это сработало. Можете ли вы объяснить свой код? Я также заметил, что вы отредактировали функцию исключения файлов с помощью re.compile. Можете ли вы объяснить, какова скорость в этом по сравнению с приведенным выше ответом? - person ; 02.08.2014
comment
Не совсем уверен, что вы хотите, чтобы я объяснил. Я буду стараться. Что касается exclude_files и format, он делает то же самое, но использует меньше временных файлов под капотом. Дополнительная логика предназначена для случаев, когда любой из них является пустым списком; вероятно, можно закодировать лучше. По поводу скорости не мерил. Можно предположить, что меньшее количество обращений к пространству имен может быть улучшением. - person FredrikHedman; 03.08.2014

Вы можете использовать ключевое слово «продолжить», чтобы пропустить итерацию при обходе с помощью os.walk («pathName»)

for dirpath, dirnames, filenames in os.walk(pathName):
    # Write regular expression or a string to skip the desired folder
    dirpath_pat = re.search(pattern, dirpath)
    if dirpath_pat:
        if dirpath_pat.group(0):
            continue
person Joydeep Roychowdhury    schedule 11.12.2019