Структура дерева каталогов списка в python?
Я знаю, что мы можем использовать os.walk()
для 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?
Ответы
Ответ 1
Здесь используется функция для форматирования:
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))
Ответ 2
Решение без вашего отступа:
for path, dirs, files in os.walk(given_path):
print path
for f in files:
print f
os.walk уже совершает нисходящую прогулку в глубину, которую вы ищете.
Игнорирование списка папок предотвращает упоминание, которое вы упоминаете.
Ответ 3
Я пришел сюда, ища то же самое, и использовал дхоббс для меня. Как способ поблагодарить сообщество, я добавил несколько аргументов для записи в файл, как сказал akshay, и сделал показ файлов необязательным, так что это не так бит вывода. Также сделал отступ необязательным аргументом, чтобы вы могли его изменить, так как некоторым нравится 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
Ответ 4
Подобно ответам выше, но для 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 на очень глубоких деревьях папок.
- Дерево лениво оценивается. Он должен вести себя хорошо на действительно широких деревьях папок. Тем не менее, непосредственные дочерние элементы данной папки не лениво оцениваются.
Редактировать:
- Добавлен бонус! критерии обратного вызова для фильтрации путей.
Ответ 5
На основании этого фантастического поста
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()
Ответ 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/
Ответ 7
В верхней части ответа dhobbs выше (fooobar.com/questions/135979/...), здесь есть дополнительная функциональность хранения результатов в файле (я лично использую его для копирования и вставки в 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(".")
Ответ 8
Вы можете выполнить команду дерева в оболочке Linux.
Монтаж:
~$sudo apt install tree
Использование в питоне
>>> import os
>>> os.system('tree <desired path>')
Пример:
>>> os.system('tree ~/Desktop/myproject')
Это дает вам более чистую структуру и визуально более всеобъемлющим и простым для ввода.
Ответ 9
Может быть, быстрее, чем @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("/")
Результаты теста на скриншоте ниже:
![enter image description here]()
Ответ 10
Это решение будет работать только в том случае, если в вашей системе установлено tree
. Однако я оставляю это решение здесь на случай, если оно поможет кому-то другому.
Вы можете указать дереву выводить древовидную структуру в виде XML (tree -X
) или JSON (tree -J
). Разумеется, JSON можно анализировать напрямую с помощью Python, а XML легко читать с помощью lxml
.
На примере следующей структуры каталогов:
[[email protected] 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
[[email protected] 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}
]
Ответ 11
Здесь вы можете найти код с таким выводом: fooobar.com/info/7865638/...
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