una - Lista de estructura de árbol de directorio en python?
recorrer directorios en python (9)
Aquí hay una función para hacer eso con el formato:
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))
Sé que podemos usar os.walk () para enumerar todos los subdirectorios o todos los archivos en un directorio. Sin embargo, me gustaría enumerar el contenido completo del árbol de directorios:
- Subdirectorio 1:
- archivo11
- archivo12
- Sub-subdirectorio 11:
- archivo111
- archivo112
- Subdirectorio 2:
- archivo21
- subdirectorio 21
- subdirectorio 22
- sub-sub-subdirectorio 221
- archivo 2211
- sub-sub-subdirectorio 221
¿Cómo lograr mejor esto en Python?
Basado en esta fantástica publicación.
http://code.activestate.com/recipes/217212-treepy-graphically-displays-the-directory-structur/
Aquí es un refinamiento para comportarse exactamente como
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()
En la parte superior de la respuesta anterior de dhobbs ( https://.com/a/9728478/624597 ), aquí hay una funcionalidad adicional de almacenamiento de resultados en un archivo (yo personalmente lo uso para copiar y pegar en FreeMind para tener una buena descripción general de la estructura, por lo tanto utilicé tabulaciones en lugar de espacios para la sangría):
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(".")
Puede ejecutar el comando ''árbol'' del shell de Linux.
Instalación:
~$sudo apt install tree
Usando en python
>>> import os
>>> os.system(''tree <desired path>'')
Ejemplo:
>>> os.system(''tree ~/Desktop/myproject'')
Esto le da una estructura más limpia y es visualmente más completo y fácil de escribir.
Similar a las respuestas anteriores, pero para python3, posiblemente legible y posiblemente extensible:
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))
Ejemplo de uso:
paths = DisplayablePath.make_tree(Path(''doc''))
for path in paths:
print(path.displayable())
Ejemplo de salida:
doc/
├── _static/
│ ├── embedded/
│ │ ├── deep_file
│ │ └── very/
│ │ └── deep/
│ │ └── folder/
│ │ └── very_deep_file
│ └── less_deep_file
├── about.rst
├── conf.py
└── index.rst
Notas
- Esto utiliza la recursión. Levantará un RecursionError en árboles de carpetas muy profundos
- El árbol es perezosamente evaluado. Debería comportarse bien en árboles de carpetas muy anchas . Sin embargo, los hijos inmediatos de una carpeta determinada no se evalúan perezosamente.
Editar:
- Bonificación añadida! Callback de criterios para el filtrado de rutas.
Tal vez más rápido que @ellockie (Tal vez)
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("/")
Edición: la captura de pantalla que probé es que:
Una solución sin tu sangría:
for path, dirs, files in os.walk(path):
print path
for f in files:
print f
os.walk ya realiza la caminata de arriba hacia abajo y en profundidad que está buscando.
Ignorar la lista de directorios evita la superposición que usted menciona.
Vine aquí buscando lo mismo y usé la respuesta de dhobbs para mí. Como una forma de agradecer a la comunidad, agregué algunos argumentos para escribir en un archivo, como pidió akshay, e hice que los archivos sean opcionales para que no sea tan poco una salida. También hizo de la sangría un argumento opcional para que pueda cambiarlo, ya que a algunos les gusta que sean 2 y otros prefieren 4.
Usó diferentes bucles para que el que no muestra los archivos no compruebe si tiene que hacerlo en cada iteración.
Espero que ayude a alguien más como la respuesta de dhobbs me ayudó. Muchas gracias.
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
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
Si alguien está interesado, esa función recursiva devuelve la estructura anidada de los diccionarios. Las claves son nombres de file system
(de directorios y archivos), los valores son:
- Sub diccionarios para directorios
- cadenas para archivos (ver
file_token
)
Las cadenas que designan archivos están vacías en este ejemplo. También pueden ser, por ejemplo, contenidos de archivo dados o su información de propietario o privilegios o cualquier objeto diferente a un dict. A menos que sea un diccionario, se puede distinguir fácilmente de un "tipo de directorio" en otras operaciones (por ejemplo, en os_walk_mock
continuación).
Teniendo tal árbol en un sistema de archivos:
# 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
El resultado será:
# 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'': {}
}
Si te gusta eso, ya he creado un paquete (python 2 y 3) con estas cosas (y un buen asistente de pyfakefs
): https://pypi.org/project/fsforge/