Структура дерева каталогов списка в python?
Я знаю, что мы можем использовать ОС.walk (), чтобы перечислить все подкаталоги или все файлы в каталоге. Тем не менее, я хотел бы перечислить полное содержимое дерева каталогов:
- поддиректорию 1:
- file11
- file12
- суб-суб-директорию 11:
- file111
- file112
- поддиректорию 2:
- file21
- суб-суб-директории 21
- суб-суб-каталог 22
- sub-sub-sub-directory 221
- 2211
- sub-sub-sub-directory 221
Как лучше всего достичь этого в Python?
9 ответов
вот функция для форматирования:
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))
решение без отступа:
for path, dirs, files in os.walk(path):
print path
for f in files:
print f
os.walk уже делает нисходящую, глубокую первую прогулку, которую вы ищете.
игнорирование списка dirs предотвращает перекрытие, которое вы упомянули.
Я пришел сюда, ища то же самое, и использовал ответ dhobbs для меня. Чтобы поблагодарить сообщество, я добавил несколько аргументов для записи в файл, как просил Акшай, и сделал показ файлов необязательным, чтобы это не было таким битным выходом. Также сделал отступ необязательным аргументом, чтобы вы могли его изменить, так как некоторые любят 2, а другие предпочитают 4.
используются разные циклы, поэтому тот, который не показывает файлы, не проверяет, должен ли он на каждой итерации.
надеюсь, это поможет кто-то еще, как ответил дхоббс, помог мне. Большое спасибо.
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
на основе этого фантастического должности
http://code.activestate.com/recipes/217212-treepy-graphically-displays-the-directory-structur/
здесь Эс уточнение вести себя в точности как
http://linux.die.net/man/1/tree
#!/usr/bin/env python2 # -*- coding: utf-8 -*- # tree.py # # Written by Doug Dahms # # Prints the tree structure for the path specified on the command line from os import listdir, sep from os.path import abspath, basename, isdir from sys import argv def tree(dir, padding, print_files=False, isLast=False, isFirst=False): if isFirst: print padding.decode('utf8')[:-1].encode('utf8') + dir else: if isLast: print padding.decode('utf8')[:-1].encode('utf8') + '└── ' + basename(abspath(dir)) else: print padding.decode('utf8')[:-1].encode('utf8') + '├── ' + basename(abspath(dir)) files = [] if print_files: files = listdir(dir) else: files = [x for x in listdir(dir) if isdir(dir + sep + x)] if not isFirst: padding = padding + ' ' files = sorted(files, key=lambda s: s.lower()) count = 0 last = len(files) - 1 for i, file in 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, False) else: tree(path, padding + '│', 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' elif len(argv) == 3 and argv[1] == '-f': # print directories and files path = argv[2] if isdir(path): tree(path, '', True, False, True) else: print 'ERROR: \'' + path + '\' is not a directory' else: print usage() if __name__ == '__main__': main()
вы можете выполнить команду "дерево" оболочки Linux.
установка:
~$sudo apt install tree
использование в python
>>> import os
>>> os.system('tree <desired path>')
пример:
>>> os.system('tree ~/Desktop/myproject')
Это дает вам более чистую структуру и визуально более всесторонний и легкий для того чтобы напечатать.
подобно ответам выше, но для 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 на самом деле глубокий папка деревьев
- дерево лениво оценены. Он должен хорошо себя вести на самом деле широкое папка деревьев. Непосредственные дети из данной папки не лениво оцениваются, хотя.
Edit:
- дополнительный бонус! критерий обратного вызова для путей фильтрации.
поверх ответа 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(".")
может быть, быстрее, чем @ellockie (может быть )
import os def file_writer(text): with open("folder_structure.txt","a") as f_output: f_output.write(text) def list_files(startpath): for root, dirs, files in os.walk(startpath): level = root.replace(startpath, '').count(os.sep) indent = '\t' * 1 * (level) output_string = '{}{}/ \n'.format(indent, os.path.basename(root)) file_writer(output_string) subindent = '\t' * 1 * (level + 1) output_string = '%s %s \n' %(subindent,[f for f in files]) file_writer(''.join(output_string)) list_files("/")
Edit: я был протестирован скриншот таков:
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
имена (каталогов и файлов), значения:
- sub словари для каталогов
- строки для файлов (см.
file_token
)
в этом примере строки, обозначающие файлы, пусты. Они также могут быть, например, содержимое файла или его владелец информация или привилегии или любой объект, отличный от dict. Если это не словарь, его можно легко отличить от "типа каталога" в дальнейших операциях (например, в os_walk_mock
ниже).
наличие такого дерева в файловой системе:
# 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:
>>> my_nice_tree = fs_tree_to_dict("/tmp/ex")
>>> my_nice_tree
{
'd_a': {
'd_a_a': {},
'd_a_b': {
'f1.txt': ''
},
'd_a_c': {},
'fa.txt': ''
},
'd_b': {
'fb1.txt': '',
'fb2.txt': ''
},
'd_c': {}
}
я написал вспомогательную функцию для создания подделки fs
структурное модульное тестирование fot (на основе real fs
) С гораздо более элегантным способом, чем фиктивный вывод os.walk
. С помощью языка Python dict
литералы отлично подходят здесь.
такой "метод" можно использовать для издевательства os.walk
С ОПРЕДЕЛЕННЫМ деревом в качестве аргумента:
def create_os_walk_mock(whole_tree):
"return a callable with same interface as os.walk()"
def actual_os_walk_interface(path_arg):
def walk_mock(tree, path_=""):
"the recursive flattening iterator"
dirs = {n: v for n, v in tree.items() if isinstance(v, dict)}
files = [n for n, v in tree.items() if not isinstance(v, dict)]
yield path_, dirs.keys(), files
for dir_name, dir_tree in dirs.items():
for result in walk_mock(dir_tree, os.path.join(path_, dir_name)):
yield result
return walk_mock(whole_tree, path_arg)
return actual_os_walk_interface
os_walk_mock = create_os_walk_mock(my_nice_tree)
list(os_walk_mock("/tmp/ex"))
>>> [
('/tmp/ex', ['d_b', 'd_c', 'd_a'], []),
('/tmp/ex/d_b', [], ['fb1.txt', 'fb2.txt']),
('/tmp/ex/d_c', [], []),
('/tmp/ex/d_a', ['d_a_a', 'd_a_b', 'd_a_c'], ['fa.txt']),
('/tmp/ex/d_a/d_a_a', [], []),
('/tmp/ex/d_a/d_a_b', [], ['f1.txt']),
('/tmp/ex/d_a/d_a_c', [], []),
]
который дает точно такой же результат, как и реальный результат list(os.walk("/tmp/ex"))
(пренебрегая порядком элементов, который всегда неопределенен при прохождении реального fs
).