web-dev-qa-db-fra.com

Arborescence de répertoires en python?

Je sais que nous pouvons utiliser os.walk () pour lister tous les sous-répertoires ou tous les fichiers d’un répertoire. Cependant, j'aimerais lister le contenu complet de l'arborescence de répertoires:

  • Sous-répertoire 1:
    • fichier11
    • fichier12
    • Sous-sous-répertoire 11:
      • fichier111
      • fichier112
  • Sous-répertoire 2:
    • fichier21
    • sous-sous-répertoire 21
    • sous-sous-répertoire 22
      • sous-sous-sous-répertoire 221
        • fiche 2211

Comment y parvenir au mieux en Python?

58
cinny

Voici une fonction pour le faire avec le formatage:

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))
90
dhobbs

Une solution sans votre indentation:

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

os.walk fait déjà la promenade de haut en bas que vous recherchez en profondeur.

Ignorer la liste des répertoires empêche le chevauchement que vous mentionnez.

17
Intra

Je suis venu ici pour chercher la même chose et utilisé dhobbs answer pour moi. Pour remercier la communauté, j’ai ajouté quelques arguments pour écrire dans un fichier, comme le demandait akshay, et j’ai rendu l’affichage facultatif des fichiers afin qu’il ne s’agisse pas d’une sortie si binaire. En outre, l'indentation est devenue un argument facultatif afin que vous puissiez le modifier, car certains le préfèrent à 2 et d'autres à 4. 

Utilisé différentes boucles afin que celui qui ne montre pas les fichiers ne vérifie pas si cela doit se faire à chaque itération.

J'espère que ça aide quelqu'un d'autre, car la réponse de dhobbs m'a aidé. Merci beaucoup.

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
9
Rubén Cabrera

Basé sur ce post fantastique 

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

Voici un raffinement à se comporter exactement comme 

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

 #!/usr/bin/env python2 
 # - * - codage: utf-8 - * -

 # tree.py 
 # 
 # # Écrit par Doug Dahms
 # 
 # Imprime l’arborescence correspondant au chemin indiqué sur la ligne de commande 

 À partir de os import listdir, sep .__ à partir de os.path import abspath, nom de base, isdir .____ argv 

 def tree (rép, padding, print_files = False, isLast = False, isFirst = False): 
 si isFirst: 
 print padding.decode ('utf8') [: - 1] .encode ('utf8') + dir 
 autre:
 si isLast: 
 print padding.decode ('utf8') [: - 1] .encode ('utf8') + '└──' + nom de base (abspath (dir)) 
 autre:
 print padding.decode ('utf8') [: - 1] .encode ('utf8') + '├──' + nom de base (abspath (dir)) 
 fichiers = [] 
 si print_files: 
 fichiers = listdir (dir) 
 autre:
 files = [x pour x dans listdir (dir) si isdir (dir + sep + x)] 
 sinon isFirst: 
 padding = padding + '' 
 fichiers = triés (fichiers, clé = lambda s: s.lower ()) 
 compte = 0 
 last = len (file) - 1 
 pour i, fichier en énumérer (fichiers): 
 compte + = 1 
 chemin = dir + sep + fichier 
 isLast = i == dernier 
 si isdir (chemin): 
 si compte == len (fichiers): 
 si isFirst: 
 tree (chemin d'accès, padding, print_files, isLast, False) 
 autre:
 tree (chemin d'accès, padding + '', print_files, isLast, False) 
 autre:
 tree (chemin d'accès, padding + '│', fichiers_impression, isLast, False) 
 autre:
 si isLast: 
 print padding + '└──' + file 
 autre:
 print padding + '├──' + file 

 def usage (): 
 return '' 'Utilisation:% s [-f] 
 Arborescence d'impression du chemin spécifié 
 Options: 
- f Imprime les fichiers ainsi que les répertoires 
 PATH Chemin d'accès au processus' ''% basename (argv [0]) 

 def main (): 
 si len (argv) == 1: 
 utilisation de l'impression () 
 Elif len (argv) == 2: 
 # imprimer seulement les annuaires 
 chemin = argv [1] 
 si isdir (chemin): 
 arbre (chemin, '', False, False, True) 
 autre:
 print 'ERROR: \' '+ path +'\'n'est pas un répertoire' 
 Elif len (argv) == 3 et argv [1] == '-f': 
 # imprimer des répertoires et des fichiers 
 chemin = argv [2] 
 si isdir (chemin): 
 arbre (chemin, '', vrai, faux, vrai) 
 autre:
 print 'ERROR: \' '+ path +'\'n'est pas un répertoire' 
 autre:
 print usage () 

 if __== '__main __': 
 principale()


5
albfan
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 quelqu'un est intéressé, cette fonction récursive renvoie la structure imbriquée de dictionnaires. Les clés sont des noms file system (de répertoires et de fichiers), les valeurs sont les suivantes:

  • sous dictionnaires pour répertoires
  • chaînes pour les fichiers (voir file_token)

Les chaînes désignant les fichiers sont vides dans cet exemple. Ils peuvent aussi être par exemple contenu du fichier donné ou les informations de son propriétaire ou des privilèges ou tout autre objet qu'un dict. À moins qu'il s'agisse d'un dictionnaire, il peut être facilement distingué d'un "type de répertoire" lors d'opérations ultérieures.

Avoir un tel arbre dans un système de fichiers:

# 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

Le résultat sera:

# 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 vous aimez ça, j'ai déjà créé un paquet (Python 2 & 3) avec ce genre de choses (et un assistant Nice pyfakefs): https://pypi.org/project/fsforge/

4
Mikaelblomkvistsson

Semblable aux réponses ci-dessus, mais pour python3, sans doute lisible et 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))

Exemple d'utilisation:

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

Exemple de sortie:

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

Remarques

  • Cela utilise la récursivité. Il va déclencher une arborescence de dossiers RecursionError on vraiment deep
  • L'arbre est évalué paresseusement. Il devrait bien se comporter sur les arborescences vraiment wide. Les enfants immédiats d'un dossier donné ne sont cependant pas évalués paresseusement.

Modifier:

  • Bonus ajouté! critères de rappel pour les chemins de filtrage.
4
abstrus

Vous pouvez exécuter la commande 'tree' de Linux Shell.

Installation:

   ~$Sudo apt install tree

Utilisation en python 

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

Exemple:

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

Cela vous donne une structure plus propre et est visuellement plus complet et facile à taper.

2

En plus de la réponse dhobbs ci-dessus ( https://stackoverflow.com/a/9728478/624597 ), voici une fonctionnalité supplémentaire permettant de stocker les résultats dans un fichier (je l'utilise personnellement pour copier et coller dans FreeMind pour avoir une bonne vue d'ensemble de la structure, j'ai donc utilisé des tabulations au lieu d'espaces pour l'indentation):

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(".")
1
ellockie

Peut-être plus rapide que @ellockie (peut-être) 

 import os 
 def file_writer (text): 
 avec open ("folder_structure.txt", "a") en tant que f_output: 
 f_output.write (text) 
 def list_files (chemin d'accès): 


 pour root, dirs, fichiers dans os.walk (startpath): 
 level = root.replace (startpath, '') .count (os.sep) 
 indent = '\ t' * 1 * (niveau) 
 output_string = '{} {}/\ n'.format (indent, os.path.basename (root)) 
 file_writer (chaîne_sortie) 
 sous-indice = '\ t' * 1 * (niveau + 1) 
 chaîne_sortie = '% s% s\n'% (sous-indent, [f pour f dans les fichiers]) 
 file_writer (''. join (output_string)) 


 list_files ("/")

Résultats du test en capture d'écran ci-dessous:

 enter image description here

1
Enes ERGUN

Ici vous pouvez trouver le code avec une sortie comme ceci: https://stackoverflow.com/a/56622847/66713

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
Igor Z

Cette solution ne fonctionnera que si vous avez installé tree sur votre système. Cependant, je laisse cette solution ici au cas où cela aiderait quelqu'un d'autre.

Vous pouvez indiquer à l’arbre de sortir l’arborescence au format XML (tree -X) ou JSON (tree -J). JSON peut bien sûr être analysé directement avec python et XML peut facilement être lu avec lxml

Avec la structure de répertoire suivante comme exemple:

[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}
]
0
shrewmouse

Pour ceux qui cherchent encore une réponse. Voici une approche récursive pour obtenir les chemins dans un dictionnaire.

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
sky