Список древовидной структуры каталогов в Python?

111

Я знаю, что мы можем использовать os.walk()для вывода списка всех подкаталогов или всех файлов в каталоге. Однако я хотел бы перечислить полное содержимое дерева каталогов:

- Subdirectory 1:
   - file11
   - file12
   - Sub-sub-directory 11:
         - file111
         - file112
- Subdirectory 2:
    - file21
    - sub-sub-directory 21
    - sub-sub-directory 22    
        - sub-sub-sub-directory 221
            - file 2211

Как лучше всего добиться этого на Python?

cinny
источник

Ответы:

148

Вот функция для этого с форматированием:

import os

def list_files(startpath):
    for root, dirs, files in os.walk(startpath):
        level = root.replace(startpath, '').count(os.sep)
        indent = ' ' * 4 * (level)
        print('{}{}/'.format(indent, os.path.basename(root)))
        subindent = ' ' * 4 * (level + 1)
        for f in files:
            print('{}{}'.format(subindent, f))
дхоббс
источник
1
Это сработало очень хорошо, спасибо. Хотя большинство будет знать, это все еще для новичков в Python - обратите внимание, что вам нужно будет вызвать функцию в конце (при условии, что окна), поэтому вы можете добавить новую строку в конце с содержимым list_files ("D: \\ ")
Рахул
1
Хорошо работал на python3. Но на python2 ValueError: zero length field name in formatвыбрасывается.
nipunasudha
3
Если startpath повторяется внутри root, не будет ли он заменять каждое вхождение? Изменение на root.replace(startpath, '', 1)должно исправить это
drone.ah
32

Подобно ответам выше, но для python3, возможно, читаемый и, возможно, расширяемый:

from pathlib import Path

class DisplayablePath(object):
    display_filename_prefix_middle = '├──'
    display_filename_prefix_last = '└──'
    display_parent_prefix_middle = '    '
    display_parent_prefix_last = '│   '

    def __init__(self, path, parent_path, is_last):
        self.path = Path(str(path))
        self.parent = parent_path
        self.is_last = is_last
        if self.parent:
            self.depth = self.parent.depth + 1
        else:
            self.depth = 0

    @property
    def displayname(self):
        if self.path.is_dir():
            return self.path.name + '/'
        return self.path.name

    @classmethod
    def make_tree(cls, root, parent=None, is_last=False, criteria=None):
        root = Path(str(root))
        criteria = criteria or cls._default_criteria

        displayable_root = cls(root, parent, is_last)
        yield displayable_root

        children = sorted(list(path
                               for path in root.iterdir()
                               if criteria(path)),
                          key=lambda s: str(s).lower())
        count = 1
        for path in children:
            is_last = count == len(children)
            if path.is_dir():
                yield from cls.make_tree(path,
                                         parent=displayable_root,
                                         is_last=is_last,
                                         criteria=criteria)
            else:
                yield cls(path, displayable_root, is_last)
            count += 1

    @classmethod
    def _default_criteria(cls, path):
        return True

    @property
    def displayname(self):
        if self.path.is_dir():
            return self.path.name + '/'
        return self.path.name

    def displayable(self):
        if self.parent is None:
            return self.displayname

        _filename_prefix = (self.display_filename_prefix_last
                            if self.is_last
                            else self.display_filename_prefix_middle)

        parts = ['{!s} {!s}'.format(_filename_prefix,
                                    self.displayname)]

        parent = self.parent
        while parent and parent.parent is not None:
            parts.append(self.display_parent_prefix_middle
                         if parent.is_last
                         else self.display_parent_prefix_last)
            parent = parent.parent

        return ''.join(reversed(parts))

Пример использования:

paths = DisplayablePath.make_tree(Path('doc'))
for path in paths:
    print(path.displayable())

Пример вывода:

doc/
├── _static/
   ├── embedded/
      ├── deep_file
      └── very/
          └── deep/
              └── folder/
                  └── very_deep_file
   └── less_deep_file
├── about.rst
├── conf.py
└── index.rst

Ноты

  • Это использует рекурсию. Это вызовет ошибку RecursionError на действительно глубоких деревьях папок.
  • Дерево лениво оценивается. Он должен хорошо себя вести на действительно широких деревьях папок. Однако непосредственные потомки данной папки не лениво оцениваются.

Редактировать:

  • Добавлен бонус! обратный вызов критериев для фильтрации путей.
abstrus
источник
Хороший инструмент, у вас есть быстрый пример того, как использовать критерии для исключения имен папок?
Matt-Mac-Muffin
Это именно то, что я искал. Спасибо вам большое!
dheinz
24

Решение без вашего отступа:

for path, dirs, files in os.walk(given_path):
  print path
  for f in files:
    print f

os.walk уже выполняет ту прогулку сверху вниз, в первую очередь в глубину, которую вы ищете.

Игнорирование списка каталогов предотвращает указанное вами перекрытие.

Intra
источник
2
питон говорит:NameError: name 'path' is not defined
Francesco Mantovani
1
@FrancescoMantovani "путь" - это переменная, содержащая каталог, который вы хотите распечатать, т.е. r "C: \ Users \ username \ Documents \ path"
zwelz
16

Список древовидной структуры каталогов в Python?

Обычно мы предпочитаем просто использовать дерево GNU, но мы не всегда используем его treeв каждой системе, и иногда доступен Python 3. Хороший ответ здесь можно легко скопировать и не делать treeтребования GNU .

treeвывод выглядит так:

$ tree
.
├── package
   ├── __init__.py
   ├── __main__.py
   ├── subpackage
      ├── __init__.py
      ├── __main__.py
      └── module.py
   └── subpackage2
       ├── __init__.py
       ├── __main__.py
       └── module2.py
└── package2
    └── __init__.py

4 directories, 9 files

Я создал указанную выше структуру каталогов в моем домашнем каталоге в каталоге, который я называю pyscratch.

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

Дерево в Python

Для начала воспользуемся примером, который

  • использует Pathобъект Python 3
  • использует yieldи yield fromвыражение (которые создают функцию генератора)
  • использует рекурсию для элегантной простоты
  • использует комментарии и некоторые аннотации типов для большей ясности
from pathlib import Path

# prefix components:
space =  '    '
branch = '│   '
# pointers:
tee =    '├── '
last =   '└── '


def tree(dir_path: Path, prefix: str=''):
    """A recursive generator, given a directory Path object
    will yield a visual tree structure line by line
    with each line prefixed by the same characters
    """    
    contents = list(dir_path.iterdir())
    # contents each get pointers that are ├── with a final └── :
    pointers = [tee] * (len(contents) - 1) + [last]
    for pointer, path in zip(pointers, contents):
        yield prefix + pointer + path.name
        if path.is_dir(): # extend the prefix and recurse:
            extension = branch if pointer == tee else space 
            # i.e. space because last, └── , above so no more |
            yield from tree(path, prefix=prefix+extension)

и сейчас:

for line in tree(Path.home() / 'pyscratch'):
    print(line)

печатает:

├── package
   ├── __init__.py
   ├── __main__.py
   ├── subpackage
      ├── __init__.py
      ├── __main__.py
      └── module.py
   └── subpackage2
       ├── __init__.py
       ├── __main__.py
       └── module2.py
└── package2
    └── __init__.py

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

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

Больше возможностей

Теперь GNU treeдает нам несколько полезных функций, которые я хотел бы иметь с помощью этой функции:

  • сначала печатает имя тематической директории (делает это автоматически, наша - нет)
  • печатает количество n directories, m files
  • возможность ограничить рекурсию, -L level
  • возможность ограничить только каталогами, -d

Кроме того, когда есть огромное дерево, полезно ограничить итерацию (например, с помощью islice), чтобы избежать блокировки вашего интерпретатора текстом, поскольку в какой-то момент вывод становится слишком подробным, чтобы быть полезным. Мы можем сделать это произвольно высоким по умолчанию, скажем 1000.

Итак, давайте удалим предыдущие комментарии и заполним эту функцию:

from pathlib import Path
from itertools import islice

space =  '    '
branch = '│   '
tee =    '├── '
last =   '└── '
def tree(dir_path: Path, level: int=-1, limit_to_directories: bool=False,
         length_limit: int=1000):
    """Given a directory Path object print a visual tree structure"""
    dir_path = Path(dir_path) # accept string coerceable to Path
    files = 0
    directories = 0
    def inner(dir_path: Path, prefix: str='', level=-1):
        nonlocal files, directories
        if not level: 
            return # 0, stop iterating
        if limit_to_directories:
            contents = [d for d in dir_path.iterdir() if d.is_dir()]
        else: 
            contents = list(dir_path.iterdir())
        pointers = [tee] * (len(contents) - 1) + [last]
        for pointer, path in zip(pointers, contents):
            if path.is_dir():
                yield prefix + pointer + path.name
                directories += 1
                extension = branch if pointer == tee else space 
                yield from inner(path, prefix=prefix+extension, level=level-1)
            elif not limit_to_directories:
                yield prefix + pointer + path.name
                files += 1
    print(dir_path.name)
    iterator = inner(dir_path, level=level)
    for line in islice(iterator, length_limit):
        print(line)
    if next(iterator, None):
        print(f'... length_limit, {length_limit}, reached, counted:')
    print(f'\n{directories} directories' + (f', {files} files' if files else ''))

И теперь мы можем получить такой же результат, как tree:

tree(Path.home() / 'pyscratch')

печатает:

pyscratch
├── package
   ├── __init__.py
   ├── __main__.py
   ├── subpackage
      ├── __init__.py
      ├── __main__.py
      └── module.py
   └── subpackage2
       ├── __init__.py
       ├── __main__.py
       └── module2.py
└── package2
    └── __init__.py

4 directories, 9 files

А мы можем ограничиться уровнями:

tree(Path.home() / 'pyscratch', level=2)

печатает:

pyscratch
├── package
   ├── __init__.py
   ├── __main__.py
   ├── subpackage
   └── subpackage2
└── package2
    └── __init__.py

4 directories, 3 files

И мы можем ограничить вывод каталогами:

tree(Path.home() / 'pyscratch', level=2, limit_to_directories=True)

печатает:

pyscratch
├── package
   ├── subpackage
   └── subpackage2
└── package2

4 directories

Ретроспектива

Оглядываясь назад, мы могли бы использовать path.globдля сопоставления. Мы могли бы также использовать path.rglobдля рекурсивной подстановки, но это потребует переписывания. Мы также могли бы использоватьitertools.tee вместо материализации список содержимого каталогов, но это может иметь отрицательные компромиссы и, вероятно, сделает код еще более сложным.

Комментарии приветствуются!

Аарон Холл
источник
Чтобы также распечатать строки кода, после elif not limit_to_directories:добавьте следующее: info = prefix + pointer + path.name; try: with path.open('r') as f: n_lines = len(f.readlines()); loc = f' LOC: {n_lines}'; info += loc; except UnicodeDecodeError: pass; yield info См. Эту ссылку для правильного белого пространства.
Стивен К. Хауэлл,
Это было именно то, что мне нужно в моем коде, и оно научило меня некоторым новым трюкам Python! Единственное, что я хотел бы отметить, это то, что contentsнужно фильтровать, если limit_to_directoriesTrue. В противном случае, если в папке нет каталога для последнего файла, дерево будет нарисовано неправильно. if limit_to_directories: contents = [path for path in contents if path.is_dir()]
hennign
@hennign спасибо, ответ обновлен, благодарю за отзыв!
Аарон Холл
Все Python основано на list(dir_path.iterdir())возврате правильно упорядоченного нисходящего дерева структуры каталогов. Я не вижу такой гарантии в API для iterdir () . Пожалуйста, дайте ссылку на то, как iterdir()заказывает или гарантированно обеспечит желаемый заказ.
ingyhere
@ingyhere Я не уверен, откуда вы взяли эту идею - кажется,os.listdir() она используется по умолчанию - что не дает гарантии порядка : «Список находится в произвольном порядке и не включает специальные записи». и '..', даже если они присутствуют в каталоге ».
Аарон Холл
15

Я пришел сюда в поисках того же и использовал для себя ответ dhobbs. Как способ поблагодарить сообщество, я добавил несколько аргументов для записи в файл, как просил Акшай, и сделал отображение файлов необязательным, поэтому это не так уж и важно. Также сделал отступ в качестве необязательного аргумента, чтобы вы могли его изменить, так как некоторым нравится значение 2, а другим - 4.

Использовались разные циклы, поэтому тот, который не показывает файлы, не проверяет, нужно ли это делать на каждой итерации.

Надеюсь, это поможет кому-то другому, поскольку ответ dhobbs помог мне. Большое спасибо.

def showFolderTree(path,show_files=False,indentation=2,file_output=False):
"""
Shows the content of a folder in a tree structure.
path -(string)- path of the root folder we want to show.
show_files -(boolean)-  Whether or not we want to see files listed.
                        Defaults to False.
indentation -(int)- Indentation we want to use, defaults to 2.   
file_output -(string)-  Path (including the name) of the file where we want
                        to save the tree.
"""


tree = []

if not show_files:
    for root, dirs, files in os.walk(path):
        level = root.replace(path, '').count(os.sep)
        indent = ' '*indentation*(level)
        tree.append('{}{}/'.format(indent,os.path.basename(root)))

if show_files:
    for root, dirs, files in os.walk(path):
        level = root.replace(path, '').count(os.sep)
        indent = ' '*indentation*(level)
        tree.append('{}{}/'.format(indent,os.path.basename(root)))    
        for f in files:
            subindent=' ' * indentation * (level+1)
            tree.append('{}{}'.format(subindent,f))

if file_output:
    output_file = open(file_output,'w')
    for line in tree:
        output_file.write(line)
        output_file.write('\n')
else:
    # Default behaviour: print on screen.
    for line in tree:
        print line
Рубен Кабрера
источник
Я чувствую, что этот ответ не способствует уже принятому ответу. Единственное, что вы предоставляете, - это дополнительный код для отключения функций в ответе.
CodeLikeBeaker
3
Ты прав, @ jason-heine. Принятый ответ достаточно хорош, но некоторые люди спрашивали, как это сделать, и я хотел им кое-что дать. Проголосуйте вниз или сообщите мой ответ, если вы не хотите видеть это в SO, я думал, что это не повредит, но я могу ошибаться.
Рубен Кабрера
3
Это действительно полезно. Большое спасибо. Я использовал его как есть.
vladblindu 01
7

На основе этого фантастического поста

http://code.activestate.com/recipes/217212-treepy-graphically-displays-the-directory-structur/

Здесь есть усовершенствование, чтобы вести себя точно так же, как

http://linux.die.net/man/1/tree

#! / usr / bin / env python2 # - * - кодировка: utf-8 - * -


# tree.py # # Написано Дугом Дамсом # # Распечатывает древовидную структуру для пути, указанного в командной строке





из os import listdir , sep
 из os . путь import abspath , basename , isdir
 from sys import argv

def tree ( dir , padding , print_files = False , isLast = False , isFirst = False ): if isFirst : печать отступов . декодировать ( 'utf8' ) [: - 1 ]. encode ( 'utf8' ) + dir
     else : if isLast : напечатать отступ . декодировать ( 'utf8' ) [: - 1 ].
    
         
        
            encode :( 'utf8' ) + '└──' + basename ( abspath ( dir )) else : напечатать отступ . декодировать ( 'utf8' ) [: - 1 ]. encode ( 'utf8' ) + '├──' + basename ( abspath ( dir )) 
    files = [] if print_files : 
        files = listdir ( dir ) else   
        
                
    
    
        files = [ x для x в listdir ( dir ), если isdir ( dir + sep + x )], если не isFirst : 
        padding = padding + '' 
    files = sorted ( files , key = lambda s : s . lower ()) 
    count = 0 
    last = len (  
       files ) - 1 для i , файл в enumerate ( files ): 
        count + = 1 
        path = dir + sep + file  
     
        isLast = i == last
         if isdir ( path ): if count == len ( files ): if isFirst : 
                    tree ( path , padding , print_files , isLast , False ) else : 
                    tree ( path , padding + ' , print_files , isLast , Ложь )
            
                 
                  
             else : 
                tree ( path , набивка+ '│', print_files, isLast, False)
        else:
            if isLast:
                print padding + '└── ' + file
            else:
                print padding + '├── ' + file

def usage():
    return '''Usage: %s [-f] 
Print tree structure of path specified.
Options:
-f      Print files as well as directories
PATH    Path to process''' % basename(argv[0])

def main():
    if len(argv) == 1:
        print usage()
    elif len(argv) == 2:
        # print just directories
        path = argv[1]
        if isdir(path):
            tree(path, '', False, False, True)
        else:
            print 'ERROR: \'' + path + '\' is not a directory'
    eliflen ( argv ) == 3 and argv [ 1 ] == '-f' : # распечатать каталоги и файлы 
        path = argv [ 2 ] if isdir ( path ): 
            tree ( path , '' , True , False , True ) else : print     
        
            
        
             'ERROR: \'' + path + '\' не является каталогом ' else : print usage ()
    
        

если __name__ == '__main__' : 
    main () 

Альфан
источник
6
import os

def fs_tree_to_dict(path_):
    file_token = ''
    for root, dirs, files in os.walk(path_):
        tree = {d: fs_tree_to_dict(os.path.join(root, d)) for d in dirs}
        tree.update({f: file_token for f in files})
        return tree  # note we discontinue iteration trough os.walk

Если кому-то интересно - та рекурсивная функция возвращает вложенную структуру словарей. Ключи - это file systemимена (каталогов и файлов), значения либо:

  • подкаталоги для справочников
  • строки для файлов (см. file_token)

В этом примере строки, обозначающие файлы, пусты. Им также может быть, например, предоставлено содержимое файла или информация о его владельце или привилегии или любой другой объект, отличный от dict. Если это не словарь, его можно легко отличить от "типа каталога" в дальнейших операциях.

Наличие такого дерева в файловой системе:

# bash:
$ tree /tmp/ex
/tmp/ex
├── d_a
   ├── d_a_a
   ├── d_a_b
      └── f1.txt
   ├── d_a_c
   └── fa.txt
├── d_b
   ├── fb1.txt
   └── fb2.txt
└── d_c

Результат будет:

# python 2 or 3:
>>> fs_tree_to_dict("/tmp/ex")
{
    'd_a': {
        'd_a_a': {},
        'd_a_b': {
            'f1.txt': ''
        },
        'd_a_c': {},
        'fa.txt': ''
    },
    'd_b': {
        'fb1.txt': '',
        'fb2.txt': ''
    },
    'd_c': {}
}

Если вам это нравится, я уже создал пакет (python 2 и 3) с этим материалом (и хорошим pyfakefsпомощником): https://pypi.org/project/fsforge/

Микаэльбломквистссон
источник
4

В дополнение к ответу dhobbs выше ( https://stackoverflow.com/a/9728478/624597 ), вот дополнительная функция сохранения результатов в файл (я лично использую его для копирования и вставки в FreeMind, чтобы иметь хороший обзор структура, поэтому я использовал табуляцию вместо пробелов для отступов):

import os

def list_files(startpath):

    with open("folder_structure.txt", "w") as f_output:
        for root, dirs, files in os.walk(startpath):
            level = root.replace(startpath, '').count(os.sep)
            indent = '\t' * 1 * (level)
            output_string = '{}{}/'.format(indent, os.path.basename(root))
            print(output_string)
            f_output.write(output_string + '\n')
            subindent = '\t' * 1 * (level + 1)
            for f in files:
                output_string = '{}{}'.format(subindent, f)
                print(output_string)
                f_output.write(output_string + '\n')

list_files(".")
эллоки
источник
этот ответ действительно помог, спасибо
prex
2

Вы можете выполнить команду tree в оболочке Linux.

Монтаж:

   ~$sudo apt install tree

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

    >>> import os
    >>> os.system('tree <desired path>')

Пример:

    >>> os.system('tree ~/Desktop/myproject')

Это дает вам более чистую структуру, визуально более полный и простой для набора текста.

Ашфак Ур Рахман Н
источник
Это не очень портативное решение, поскольку оно не работает в Windows + полагается на дополнительную программу
oglop
2

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

Вы можете указать дереву выводить древовидную структуру как XML ( tree -X) или JSON ( tree -J). Разумеется, JSON можно анализировать напрямую с помощью Python, а XML можно легко читать lxml.

На примере следующей структуры каталогов:

[sri@localhost Projects]$ tree --charset=ascii bands
bands
|-- DreamTroll
|   |-- MattBaldwinson
|   |-- members.txt
|   |-- PaulCarter
|   |-- SimonBlakelock
|   `-- Rob Stringer
|-- KingsX
|   |-- DougPinnick
|   |-- JerryGaskill
|   |-- members.txt
|   `-- TyTabor
|-- Megadeth
|   |-- DaveMustaine
|   |-- DavidEllefson
|   |-- DirkVerbeuren
|   |-- KikoLoureiro
|   `-- members.txt
|-- Nightwish
|   |-- EmppuVuorinen
|   |-- FloorJansen
|   |-- JukkaNevalainen
|   |-- MarcoHietala
|   |-- members.txt
|   |-- TroyDonockley
|   `-- TuomasHolopainen
`-- Rush
    |-- AlexLifeson
    |-- GeddyLee
    `-- NeilPeart

5 directories, 25 files

XML

<?xml version="1.0" encoding="UTF-8"?>
<tree>
  <directory name="bands">
    <directory name="DreamTroll">
      <file name="MattBaldwinson"></file>
      <file name="members.txt"></file>
      <file name="PaulCarter"></file>
      <file name="RobStringer"></file>
      <file name="SimonBlakelock"></file>
    </directory>
    <directory name="KingsX">
      <file name="DougPinnick"></file>
      <file name="JerryGaskill"></file>
      <file name="members.txt"></file>
      <file name="TyTabor"></file>
    </directory>
    <directory name="Megadeth">
      <file name="DaveMustaine"></file>
      <file name="DavidEllefson"></file>
      <file name="DirkVerbeuren"></file>
      <file name="KikoLoureiro"></file>
      <file name="members.txt"></file>
    </directory>
    <directory name="Nightwish">
      <file name="EmppuVuorinen"></file>
      <file name="FloorJansen"></file>
      <file name="JukkaNevalainen"></file>
      <file name="MarcoHietala"></file>
      <file name="members.txt"></file>
      <file name="TroyDonockley"></file>
      <file name="TuomasHolopainen"></file>
    </directory>
    <directory name="Rush">
      <file name="AlexLifeson"></file>
      <file name="GeddyLee"></file>
      <file name="NeilPeart"></file>
    </directory>
  </directory>
  <report>
    <directories>5</directories>
    <files>25</files>
  </report>
</tree>

JSON

[sri@localhost Projects]$ tree -J bands
[
  {"type":"directory","name":"bands","contents":[
    {"type":"directory","name":"DreamTroll","contents":[
      {"type":"file","name":"MattBaldwinson"},
      {"type":"file","name":"members.txt"},
      {"type":"file","name":"PaulCarter"},
      {"type":"file","name":"RobStringer"},
      {"type":"file","name":"SimonBlakelock"}
    ]},
    {"type":"directory","name":"KingsX","contents":[
      {"type":"file","name":"DougPinnick"},
      {"type":"file","name":"JerryGaskill"},
      {"type":"file","name":"members.txt"},
      {"type":"file","name":"TyTabor"}
    ]},
    {"type":"directory","name":"Megadeth","contents":[
      {"type":"file","name":"DaveMustaine"},
      {"type":"file","name":"DavidEllefson"},
      {"type":"file","name":"DirkVerbeuren"},
      {"type":"file","name":"KikoLoureiro"},
      {"type":"file","name":"members.txt"}
    ]},
    {"type":"directory","name":"Nightwish","contents":[
      {"type":"file","name":"EmppuVuorinen"},
      {"type":"file","name":"FloorJansen"},
      {"type":"file","name":"JukkaNevalainen"},
      {"type":"file","name":"MarcoHietala"},
      {"type":"file","name":"members.txt"},
      {"type":"file","name":"TroyDonockley"},
      {"type":"file","name":"TuomasHolopainen"}
    ]},
    {"type":"directory","name":"Rush","contents":[
      {"type":"file","name":"AlexLifeson"},
      {"type":"file","name":"GeddyLee"},
      {"type":"file","name":"NeilPeart"}
    ]}
  ]},
  {"type":"report","directories":5,"files":25}
]
землеройка
источник
1

Может быть, быстрее, чем @ellockie (Может быть)

импорт ОС
def file_writer (текст):
    с open ("folder_structure.txt", "a") как f_output:
        f_output.write (текст)
def list_files (начальный путь):


    для root, dirs, файлов в os.walk (startpath):
        level = root.replace (начальный путь, '') .count (os.sep)
        indent = '\ t' * 1 * (уровень)
        output_string = '{} {} / \ n'.format (отступ, os.path.basename (корень))
        file_writer (строка_вывода)
        субиндент = '\ t' * 1 * (уровень + 1)
        output_string = '% s% s \ n'% (субиндент, [f для f в файлах])
        file_writer (''. join (строка_вывода))


list_files ("/")

Результаты теста на скриншоте ниже:

введите описание изображения здесь

Энес ЭРГУН
источник
0

Здесь вы можете найти код с таким выводом: https://stackoverflow.com/a/56622847/6671330

V .
|-> V folder1
|   |-> V folder2
|   |   |-> V folder3
|   |   |   |-> file3.txt
|   |   |-> file2.txt
|   |-> V folderX
|   |-> file1.txt
|-> 02-hw1_wdwwfm.py
|-> 06-t1-home1.py
|-> 06-t1-home2.py
|-> hw1.py
Игорь З
источник
0

Для тех, кто все еще ищет ответ. Вот рекурсивный подход для получения путей в словаре.

import os


def list_files(startpath):
    for root, dirs, files in os.walk(startpath):
        dir_content = []
        for dir in dirs:
            go_inside = os.path.join(startpath, dir)
            dir_content.append(list_files(go_inside))
        files_lst = []
        for f in files:
            files_lst.append(f)
        return {'name': root, 'files': files_lst, 'dirs': dir_content}
небо
источник
0

Ответ @dhobbs отличный!

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

def print_list_dir(dir):
    print("=" * 64)
    print("[PRINT LIST DIR] %s" % dir)
    print("=" * 64)
    for root, dirs, files in os.walk(dir):
        level = root.replace(dir, '').count(os.sep)
        indent = '| ' * level
        print('{}{} \\'.format(indent, os.path.basename(root)))
        subindent = '| ' * (level + 1)
        for f in files:
            print('{}{}'.format(subindent, f))
    print("=" * 64)

и вывод вроде

================================================================
[PRINT LIST DIR] ./
================================================================
 \
| os_name.py
| json_loads.py
| linspace_python.py
| list_file.py
| to_gson_format.py
| type_convert_test.py
| in_and_replace_test.py
| online_log.py
| padding_and_clipping.py
| str_tuple.py
| set_test.py
| script_name.py
| word_count.py
| get14.py
| np_test2.py
================================================================

вы можете получить уровень по |счету!

Колин Ван
источник