os.walk без скрытых папок

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

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

Кроссплатформенность для меня не очень важна, все в порядке, если она работает только для Linux (шаблон .*)


person unddoch    schedule 19.11.2012    source источник
comment
На какой платформе вы находитесь? «скрытый» имеет разные значения в разных операционных системах.   -  person Martijn Pieters    schedule 19.11.2012
comment
Я на Linux, я добавлю это в ответ.   -  person unddoch    schedule 19.11.2012


Ответы (3)


Нет, os.walk() нельзя их пропустить. Вам нужно будет сделать это самостоятельно (что достаточно просто):

for root, dirs, files in os.walk(path):
    files = [f for f in files if not f[0] == '.']
    dirs[:] = [d for d in dirs if not d[0] == '.']
    # use files and dirs

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

Это работает, только если вы сохраните аргумент ключевого слова topdown равным True из документации os.walk():

Когда topdown равно True, вызывающая сторона может изменить список имен каталогов на месте (возможно, используя del или назначение фрагмента), а walk() будет рекурсивно обращаться только к подкаталогам, имена которых остаются в именах каталогов; это можно использовать для сокращения поиска, установления определенного порядка посещения или даже для информирования walk() о каталогах, которые вызывающая сторона создает или переименовывает, прежде чем он снова возобновит walk().

person Martijn Pieters    schedule 19.11.2012
comment
Большое спасибо, не знал, что можно изменять списки на месте! - person unddoch; 19.11.2012
comment
Я запустил это, но он ничего не вывел на консоль. Каков типичный способ отображения файлов, найденных таким образом? Я добавил print root, dirs, files в конце, но получилось очень грязно. - person user5359531; 17.06.2016
comment
@ user5359531: это полностью зависит от вашего варианта использования; вы могли бы print '\n'.join([os.path.join(root, f) for f in dirs + files]) и т. д. - person Martijn Pieters; 17.06.2016
comment
Вандер может files = [f for f in files if not f[0] == '.'] писать как files[:] = [f for f in files if not f[0] == '.'], так и dirs[:] ? - person linrongbin; 18.09.2018
comment
@linrongbin: вы могли бы, но в этом не было бы никакого преимущества. files = [...] привязывает files к новому списку, а files[:] = [...] заменяет элементы в списке, к которому уже привязан files. Никакой другой код не использует этот список, когда os.walk() дает его вам. dirs, с другой стороны, используется os.walk() для поиска следующих каталогов для перехода и создания файлов, поэтому, если вы не использовали dirs[:] = [...], то каталоги, начинающиеся с ., все равно будут посещены. - person Martijn Pieters; 18.09.2018
comment
@MartijnPieters Круто, спасибо, я не так хорошо знаком с python. - person linrongbin; 19.09.2018
comment
@linrongbin: см. также nedbatchelder.com/text/names.html, чтобы понять, как работают переменные Python. ; это поможет понять, как взаимодействуют реализация os.walk() и dir[:] = [...]. - person Martijn Pieters; 19.09.2018

Я понимаю, что это не было задано в вопросе, но у меня была аналогичная проблема, когда я хотел исключить как скрытые файлы, так и файлы, начинающиеся с __, в частности, каталоги __pycache__. Я остановился на этом вопросе, потому что пытался понять, почему мое понимание списка не делает того, что я ожидал. Я не изменял список на месте с помощью dirnames[:].

Я создал список префиксов, которые хотел исключить, и изменил имена каталогов следующим образом:

    exclude_prefixes = ('__', '.')  # exclusion prefixes
    for dirpath, dirnames, filenames in os.walk(node):
        # exclude all dirs starting with exclude_prefixes
        dirnames[:] = [dirname
                       for dirname in dirnames
                       if not dirname.startswith(exclude_prefixes)]
person dmmfll    schedule 11.08.2014
comment
это отличный ответ, отлично работает для исключения по списку - person jpw; 17.02.2016
comment
К вашему сведению, startswith также может принимать кортеж строк, поэтому вы можете избавиться от внутреннего цикла for и просто использовать not dirname.startswith(exclude_prefixes) docs.python.org/2/library/stdtypes.html#str.startswith (python 2.5 и выше) - person Daniel Rucci; 14.11.2016

Мой вариант использования был аналогичен варианту OP, за исключением того, что я хотел вернуть общее количество подкаталогов внутри определенной папки. В моем случае я хотел опустить любые подкаталоги с именем .git (а также любые папки, которые могут быть вложены в эти папки .git).

В Python 3.6.7 я обнаружил, что подход с принятым ответом не работает — он учитывает все папки .git и их подпапки. Вот что сработало для меня:

num_local_subdir = 0
for root, dirs, files in os.walk(local_folder_path):
    if '.git' in dirs:
        dirs.remove('.git')
    num_local_subdir += (len(dirs))
person James Dellinger    schedule 29.05.2019