Как использовать os.scandir() для рекурсивного возврата объектов DirEntry в дерево каталогов?

Функция Python 3.5 os.scandir(path) возвращает облегченные объекты DirEntry, которые очень полезны для информации о файлах. Тем не менее, он работает только для непосредственного пути, переданного ему. Есть ли способ обернуть его в рекурсивную функцию, чтобы он посещал все подкаталоги под заданным путем?

Ответ 1

Вы можете сканировать рекурсивно, используя os.walk(), или если вам нужны объекты DirEntry или больше, напишите рекурсивную функцию, например scantree() ниже:

try:
    from os import scandir
except ImportError:
    from scandir import scandir  # use scandir PyPI module on Python < 3.5

def scantree(path):
    """Recursively yield DirEntry objects for given directory."""
    for entry in scandir(path):
        if entry.is_dir(follow_symlinks=False):
            yield from scantree(entry.path)  # see below for Python 2.x
        else:
            yield entry

if __name__ == '__main__':
    import sys
    for entry in scantree(sys.argv[1] if len(sys.argv) > 1 else '.'):
        print(entry.path)

Примечания:

  • Есть еще несколько примеров в PEP 471 и в os.scandir() docs.
  • Вы также можете добавить логику в цикле for, чтобы пропустить каталоги или файлы, начинающиеся с '.' и такие вещи.
  • Обычно для is_dir() вызовов в рекурсивных функциях, подобных этому, обычно требуется follow_symlinks=false, чтобы избежать циклы ссылок.
  • В Python 2.x замените строку yield from на:

    for entry in scantree(entry.path):
        yield entry