Os.walk, не копаясь в каталогах ниже

Как мне ограничить os.walk возвратом файлов только из того каталога, который я ему предоставил?

def _dir_list(self, dir_name, whitelist):
    outputList = []
    for root, dirs, files in os.walk(dir_name):
        for f in files:
            if os.path.splitext(f)[1] in whitelist:
                outputList.append(os.path.join(root, f))
            else:
                self._email_to_("ignore")
    return outputList

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

antred 31.10.2016 22:26
files_with_full_path = [f.path for f in os.scandir(dir) if f.is_file()]. Если вам нужны только имена файлов, используйте f.name вместо f.path. Это самое быстрое решение и намного быстрее, чем любой walk или listdir, см. stackoverflow.com/a/40347279/2441026.
user136036 24.01.2020 16:08
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
112
2
128 937
21
Перейти к ответу Данный вопрос помечен как решенный

Ответы 21

Вы можете использовать os.listdir(), который возвращает список имен (как для файлов, так и для каталогов) в данном каталоге. Если вам нужно различать файлы и каталоги, вызывайте os.stat() для каждого имени.

Не используйте os.walk.

Пример:

import os

root = "C:\\"
for item in os.listdir(root):
    if os.path.isfile(os.path.join(root, item)):
        print item

@ 576i: это не делает различий между файлами и каталогами

user1329187 03.06.2016 12:07

@Alexandr os.path.isfile и os.path.isdir позволяют различать. Я не понимаю, так как os.path.isfile находится в образце кода с '08, а ваш комментарий от '16. Это явно лучший ответ, поскольку вы не собираетесь просматривать каталог, а хотите его перечислить.

Daniel F 29.08.2017 11:17

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

user1329187 29.08.2017 16:09

Ах хорошо. На самом деле ответ Алекса кажется лучше (с использованием .next()), и он намного ближе к вашей идее.

Daniel F 29.08.2017 16:54

Python 3.5 имеет функцию os.scandir, которая обеспечивает более сложное взаимодействие файла или каталога-объекта. См. мой ответ ниже

ascripter 27.05.2019 15:32

Предложение использовать listdir - хорошее. Прямой ответ на ваш вопрос в Python 2 - root, dirs, files = os.walk(dir_name).next().

Эквивалентный синтаксис Python 3 - root, dirs, files = next(os.walk(dir_name))

О, я получал от этого какую-то забавную ошибку. ValueError: слишком много значений для распаковки

Setori 24.10.2008 05:34

Хороший! Хотя по ощущениям хакер. Например, когда вы включаете двигатель, но даете ему сделать только один оборот, а затем вытаскиваете ключ, чтобы он умер.

Daniel F 29.08.2017 11:24

Наткнулся на это; root, dirs, files = os.walk(dir_name).next() дает мне AttributeError: 'generator' object has no attribute 'next'

Evan 27.11.2018 03:51

@Evan, вероятно, потому, что это из 2008 года и использует синтаксис Python 2. В Python 3 вы можете написать root, dirs, files = next(os.walk(dir_name)), и тогда переменные root, dirs, files будут соответствовать только переменным генератора на уровне dir_name.

CervEd 01.03.2019 15:12

Если у вас есть более сложные требования, чем только верхний каталог (например, игнорировать каталоги VCS и т. д.), Вы также можете изменить список каталогов, чтобы предотвратить повторное прохождение через них os.walk.

то есть:

def _dir_list(self, dir_name, whitelist):
    outputList = []
    for root, dirs, files in os.walk(dir_name):
        dirs[:] = [d for d in dirs if is_good(d)]
        for f in files:
            do_stuff()

Примечание - будьте осторожны, чтобы изменить список, а не просто перепривязать его. Очевидно, что os.walk не знает о внешнем перепривязке.

Ответ принят как подходящий

Используйте функцию walklevel.

import os

def walklevel(some_dir, level=1):
    some_dir = some_dir.rstrip(os.path.sep)
    assert os.path.isdir(some_dir)
    num_sep = some_dir.count(os.path.sep)
    for root, dirs, files in os.walk(some_dir):
        yield root, dirs, files
        num_sep_this = root.count(os.path.sep)
        if num_sep + level <= num_sep_this:
            del dirs[:]

Он работает так же, как os.walk, но вы можете передать ему параметр level, который указывает, насколько глубока рекурсия.

Действительно ли эта функция «проходит» по всей структуре, а затем удаляет записи ниже определенной точки? Или творится что-то более умное? Я даже не знаю, как это проверить с помощью кода. --python новичок

mathtick 19.08.2010 22:05

@mathtick: когда какой-либо каталог находится на желаемом уровне или ниже, все его подкаталоги удаляются из списка подкаталогов для следующего поиска. Так что они не будут "гулять".

nosklo 19.08.2010 23:41

Я просто поставил +1, потому что не мог "удалить" каталоги. Я пробовал dirs = [] и dirs = None, но они не работали. map(dirs.remove, dirs) работал, но с некоторыми напечатанными нежелательными сообщениями «[None]». Итак, почему именно del dirs[:]?

Zach Young 12.10.2012 04:53

отличный ответ. +1 только потому, что он работает с любым кодом, использующим os.walk.

idanshmu 10.12.2014 16:09

Отличная функция - действительно полезная

Doron Shai 21.10.2015 17:37

Обратите внимание, что это не работает при использовании topdown=False в os.walk. См. 4-й абзац в документы: Modifying dirnames when topdown is False has no effect on the behavior of the walk, because in bottom-up mode the directories in dirnames are generated before dirpath itself is generated.

dthor 25.02.2016 00:58

Я люблю это

codyc4321 21.08.2017 22:03

@ZacharyYoung dirs = [] и dirs = None не будут работать, потому что они просто создают новый несвязанный объект и присваивают имя dirs. Необходимо изменить на месте исходный объект списка, а не имя dirs.

nosklo 01.10.2018 19:34

Как я могу распечатать каталоги уровня 1 в этом скрипте python с учетом допустимой папки? Подождите, мне нужно научиться использовать урожай.

Timo 24.12.2020 21:03

Вы также можете сделать следующее:

for path, subdirs, files in os.walk(dir_name):
    for name in files:
        if path == ".": #this will filter the files in the current directory
             #code here

Не будет ли эта процедура без надобности перебирать все подкаталоги и файлы?

Pieter 27.02.2016 12:37

Я думаю, что решение на самом деле очень простое.

использовать

break

чтобы выполнить только первую итерацию цикла for, должен быть более элегантный способ.

for root, dirs, files in os.walk(dir_name):
    for f in files:
        ...
        ...
    break
...

В первый раз, когда вы вызываете os.walk, он возвращает тюльпаны для текущего каталога, а затем в следующем цикле содержимое следующего каталога.

Возьмите оригинальный скрипт и просто добавьте перерыв.

def _dir_list(self, dir_name, whitelist):
    outputList = []
    for root, dirs, files in os.walk(dir_name):
        for f in files:
            if os.path.splitext(f)[1] in whitelist:
                outputList.append(os.path.join(root, f))
            else:
                self._email_to_("ignore")
        break
    return outputList

Это должен был быть принятый ответ. Простое добавление «break» после цикла «for f in files» останавливает рекурсивность. Вы также можете убедиться, что topdown = True.

Alecz 31.10.2016 22:41

Та же идея с listdir, но короче:

[f for f in os.listdir(root_dir) if os.path.isfile(os.path.join(root_dir, f))]

Вот как я это решил

if recursive:
    items = os.walk(target_directory)
else:
    items = [next(os.walk(target_directory))]

...

При использовании listdir есть загвоздка. Os.path.isdir (идентификатор) должен быть абсолютным путем. Чтобы выбрать подкаталоги, выполните следующие действия:

for dirname in os.listdir(rootdir):
  if os.path.isdir(os.path.join(rootdir, dirname)):
     print("I got a subdirectory: %s" % dirname)

Альтернативой является переход в каталог для проведения тестирования без os.path.join ().

В Python 3 мне удалось это сделать:

import os
dir = "/path/to/files/"

#List all files immediately under this folder:
print ( next( os.walk(dir) )[2] )

#List all folders immediately under this folder:
print ( next( os.walk(dir) )[1] )

Это также работает для Python 2. Как получить второй уровень?

user1329187 03.06.2016 12:09
for path, dirs, files in os.walk('.'):
    print path, dirs, files
    del dirs[:] # go only one level deep

Вы можете использовать этот фрагмент

for root, dirs, files in os.walk(directory):
    if level > 0:
        # do some stuff
    else:
        break
    level-=1

Я чувствовал себя так, как будто бросил свои 2 пенса.

baselevel = len(rootdir.split("\\"))
for subdirs, dirs, files in os.walk(rootdir):
    curlevel = len(subdirs.split("\\"))
    if curlevel <= baselevel + 1:
        [do stuff]

создать список исключений, использовать fnmatch, чтобы пропустить структуру каталогов и выполнить процесс

excludes= ['a\*\b', 'c\d\e']
for root, directories, files in os.walk('Start_Folder'):
    if not any(fnmatch.fnmatch(nf_root, pattern) for pattern in excludes):
        for root, directories, files in os.walk(nf_root):
            ....
            do the process
            ....

то же, что и для "включает":

if **any**(fnmatch.fnmatch(nf_root, pattern) for pattern in **includes**):

Почему бы просто не использовать range и os.walk в сочетании с zip? Не лучшее решение, но тоже подойдет.

Например так:

# your part before
for count, (root, dirs, files) in zip(range(0, 1), os.walk(dir_name)):
    # logic stuff
# your later part

У меня работает на python 3.

Также: break, кстати, тоже попроще. (Посмотрите ответ от @Pieter)

Небольшое изменение в ответе Алекса, но с использованием __next__():

print(next(os.walk('d:/'))[2]) или же print(os.walk('d:/').__next__()[2])

с [2], являющимся file в root, dirs, file, упомянутым в других ответах

Поскольку Python 3.5, вы можете использовать os.scandir вместо os.listdir. Вместо строк вы получаете взамен итератор объектов DirEntry. Из документов:

Using scandir() instead of listdir() can significantly increase the performance of code that also needs file type or file attribute information, because DirEntry objects expose this information if the operating system provides it when scanning a directory. All DirEntry methods may perform a system call, but is_dir() and is_file() usually only require a system call for symbolic links; DirEntry.stat() always requires a system call on Unix but only requires one for symbolic links on Windows.

Вы можете получить доступ к имени объекта через DirEntry.name, которое тогда эквивалентно выводу os.listdir

Вы не только «можете» использовать, вы должен используете scandir(), так как это много быстрее, чем listdir(). Смотрите тесты здесь: stackoverflow.com/a/40347279/2441026.

user136036 24.01.2020 16:02

корневая папка изменяется для каждого каталога, который находит os.walk. Я решил эту проверку, если root == directory

def _dir_list(self, dir_name, whitelist):
    outputList = []
    for root, dirs, files in os.walk(dir_name):
        if root == dir_name: #This only meet parent folder
            for f in files:
                if os.path.splitext(f)[1] in whitelist:
                    outputList.append(os.path.join(root, f))
                else:
                    self._email_to_("ignore")
    return outputList
import os

def listFiles(self, dir_name):
    names = []
    for root, directory, files in os.walk(dir_name):
        if root == dir_name:
            for name in files:
                names.append(name)
    return names

Привет, Рич, добро пожаловать в Stack Overflow! Спасибо за этот фрагмент кода, который может предоставить некоторую краткосрочную помощь. Правильное объяснение значительно улучшит его долгосрочной ценности, показывающее, почему это хорошее решение проблемы, и сделало бы его более полезным для будущих читателей с другими подобными вопросами. Пожалуйста, редактировать свой ответ, чтобы добавить некоторые пояснения, включая сделанные вами предположения.

kenny_k 30.09.2019 23:44

Это хороший пример Python

def walk_with_depth(root_path, depth):
        if depth < 0:
            for root, dirs, files in os.walk(root_path):
                yield [root, dirs[:], files]

            return

        elif depth == 0:
            return

        base_depth = root_path.rstrip(os.path.sep).count(os.path.sep)
        for root, dirs, files in os.walk(root_path):
            yield [root, dirs[:], files]

            cur_depth = root.count(os.path.sep)
            
            if base_depth + depth <= cur_depth:
                del dirs[:]

Другие вопросы по теме