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

21 ответ

Решение

Использовать 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 параметр, который указывает, насколько глубокой будет рекурсия.

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

Пример:

import os

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

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

использование

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

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

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

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

Если у вас есть более сложные требования, чем просто верхний каталог (например, игнорируйте каталоги 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 не знает о внешней привязке.

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

Чувствовал, как бросить мои 2 пенса.

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

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

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

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

С помощью scandir() вместо listdir() может значительно повысить производительность кода, который также нуждается в типе файла или информации об атрибуте файла, потому что DirEntry объекты предоставляют эту информацию, если операционная система предоставляет ее при сканировании каталога. Все DirEntry методы могут выполнять системный вызов, но is_dir() а также is_file() обычно требуется только системный вызов для символических ссылок; DirEntry.stat() всегда требует системного вызова в Unix, но требует только одного для символических ссылок в Windows.

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

Корневая папка изменяется для каждого каталога, который находит 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

В 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] )

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

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

Почему бы просто не использовать 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

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

Также break проще тоже между прочим (Посмотрите на ответ от @Pieter)

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

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

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

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

Это хороший пример 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[:]

Есть ловушка при использовании 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().

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

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

Создайте список исключений, используйте 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**):

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

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

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