Usando os.walk () para recorrer recursivamente directorios en Python


151

Quiero navegar desde el directorio raíz a todos los demás directorios dentro e imprimir lo mismo.

Aquí está mi código:

#!/usr/bin/python

import os
import fnmatch

for root, dir, files in os.walk("."):
        print root
        print ""
        for items in fnmatch.filter(files, "*"):
                print "..." + items
        print ""

Y aquí está mi O / P:

.

...Python_Notes
...pypy.py
...pypy.py.save
...classdemo.py
....goutputstream-J9ZUXW
...latest.py
...pack.py
...classdemo.pyc
...Python_Notes~
...module-demo.py
...filetype.py

./packagedemo

...classdemo.py
...__init__.pyc
...__init__.py
...classdemo.pyc

Arriba, .y ./packagedemoson directorios.

Sin embargo, necesito imprimir el O / P de la siguiente manera:

A
---a.txt
---b.txt
---B
------c.out

Arriba, Ay Bson directorios y el resto son archivos.


66
Me gustaría agregar esta pequeña publicación aquí, sobre el poder de python: >>> print 2 * '-' ----
Nitaai

Respuestas:


228

Esto te dará el resultado deseado

#!/usr/bin/python

import os

# traverse root directory, and list directories as dirs and files as files
for root, dirs, files in os.walk("."):
    path = root.split(os.sep)
    print((len(path) - 1) * '---', os.path.basename(root))
    for file in files:
        print(len(path) * '---', file)

66
path = os.path.relpath (root, basepath) .split (os.sep)
Semprini

9
@Ajay sea paranoico y siempre lo haga os.walk(u".")porque las rutas pueden ser Unicode.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功 24/14

3
Mejor aún,os.path.curdir
Jir

Lo había estado usando os.path.walkdurante un tiempo, ¡así que os.walkes nuevo para mí! Frijoles fríos.
Tom

@Semprini, ¿a qué basepathequivale en su código?
stelios

23

prueba esto:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""FileTreeMaker.py: ..."""

__author__  = "legendmohe"

import os
import argparse
import time

class FileTreeMaker(object):

    def _recurse(self, parent_path, file_list, prefix, output_buf, level):
        if len(file_list) == 0 \
            or (self.max_level != -1 and self.max_level <= level):
            return
        else:
            file_list.sort(key=lambda f: os.path.isfile(os.path.join(parent_path, f)))
            for idx, sub_path in enumerate(file_list):
                if any(exclude_name in sub_path for exclude_name in self.exn):
                    continue

                full_path = os.path.join(parent_path, sub_path)
                idc = "┣━"
                if idx == len(file_list) - 1:
                    idc = "┗━"

                if os.path.isdir(full_path) and sub_path not in self.exf:
                    output_buf.append("%s%s[%s]" % (prefix, idc, sub_path))
                    if len(file_list) > 1 and idx != len(file_list) - 1:
                        tmp_prefix = prefix + "┃  "
                    else:
                        tmp_prefix = prefix + "    "
                    self._recurse(full_path, os.listdir(full_path), tmp_prefix, output_buf, level + 1)
                elif os.path.isfile(full_path):
                    output_buf.append("%s%s%s" % (prefix, idc, sub_path))

    def make(self, args):
        self.root = args.root
        self.exf = args.exclude_folder
        self.exn = args.exclude_name
        self.max_level = args.max_level

        print("root:%s" % self.root)

        buf = []
        path_parts = self.root.rsplit(os.path.sep, 1)
        buf.append("[%s]" % (path_parts[-1],))
        self._recurse(self.root, os.listdir(self.root), "", buf, 0)

        output_str = "\n".join(buf)
        if len(args.output) != 0:
            with open(args.output, 'w') as of:
                of.write(output_str)
        return output_str

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-r", "--root", help="root of file tree", default=".")
    parser.add_argument("-o", "--output", help="output file name", default="")
    parser.add_argument("-xf", "--exclude_folder", nargs='*', help="exclude folder", default=[])
    parser.add_argument("-xn", "--exclude_name", nargs='*', help="exclude name", default=[])
    parser.add_argument("-m", "--max_level", help="max level",
                        type=int, default=-1)
    args = parser.parse_args()
    print(FileTreeMaker().make(args))

obtendrás esto:

root:.
[.]
┣━[.idea]
  ┣━[scopes]
    ┗━scope_settings.xml
  ┣━.name
  ┣━Demo.iml
  ┣━encodings.xml
  ┣━misc.xml
  ┣━modules.xml
  ┣━vcs.xml
  ┗━workspace.xml
┣━[test1]
  ┗━test1.txt
┣━[test2]
  ┣━[test2-2]
    ┗━[test2-3]
        ┣━test2
        ┗━test2-3-1
  ┗━test2
┣━folder_tree_maker.py
┗━tree.py

Hola, realmente amo tu script, pero es un poco demasiado complicado para el proyecto en el que estoy trabajando, ¿hay alguna posibilidad de que pueda tenerlo como una pequeña función, con solo el argumento -r presente?
jeff_h

¿Cómo imprimirlo en un .txt? Lo intenté print(FileTreeMaker().make(args),file=tree)pero me da'charmap' codec can't encode characters in position 17-21: character maps to <undefined>
Luis Felipe

¿Qué significa idc?
voces

Escribí algo similar con os.listdir()también. El tuyo es mucho mejor; No pude entender bien la recursión, solo funcionó con 2 o 3 capas de profundidad. Al final decidí volver a intentarlo desde cero os.walk(), lo que pensé que sería mucho más adecuado. Me sorprende que no lo hayas usado aquí.
voces

11

Hay funciones más adecuadas para esto en el ospaquete. Pero si tienes que usaros.walk , esto es lo que se me ocurre

def walkdir(dirname):
    for cur, _dirs, files in os.walk(dirname):
        pref = ''
        head, tail = os.path.split(cur)
        while head:
            pref += '---'
            head, _tail = os.path.split(head)
        print(pref+tail)
        for f in files:
            print(pref+'---'+f)

salida:

>>> walkdir('.')
.
---file3
---file2
---my.py
---file1
---A
------file2
------file1
---B
------file3
------file2
------file4
------file1
---__pycache__
------my.cpython-33.pyc

55
Entonces, ¿cuáles son las funciones más adecuadas? (en 3.5 si eso importa)
Al Lelopath

Lo siento, no hay posibilidad de recordar lo que quise decir con eso. Es posible que quisiera decir, os.listdirpero la solución de @ ajay supera eso.
zaquest

5

Puede usar os.walk, y esa es probablemente la solución más fácil, pero aquí hay otra idea para explorar:

import sys, os

FILES = False

def main():
    if len(sys.argv) > 2 and sys.argv[2].upper() == '/F':
        global FILES; FILES = True
    try:
        tree(sys.argv[1])
    except:
        print('Usage: {} <directory>'.format(os.path.basename(sys.argv[0])))

def tree(path):
    path = os.path.abspath(path)
    dirs, files = listdir(path)[:2]
    print(path)
    walk(path, dirs, files)
    if not dirs:
        print('No subfolders exist')

def walk(root, dirs, files, prefix=''):
    if FILES and files:
        file_prefix = prefix + ('|' if dirs else ' ') + '   '
        for name in files:
            print(file_prefix + name)
        print(file_prefix)
    dir_prefix, walk_prefix = prefix + '+---', prefix + '|   '
    for pos, neg, name in enumerate2(dirs):
        if neg == -1:
            dir_prefix, walk_prefix = prefix + '\\---', prefix + '    '
        print(dir_prefix + name)
        path = os.path.join(root, name)
        try:
            dirs, files = listdir(path)[:2]
        except:
            pass
        else:
            walk(path, dirs, files, walk_prefix)

def listdir(path):
    dirs, files, links = [], [], []
    for name in os.listdir(path):
        path_name = os.path.join(path, name)
        if os.path.isdir(path_name):
            dirs.append(name)
        elif os.path.isfile(path_name):
            files.append(name)
        elif os.path.islink(path_name):
            links.append(name)
    return dirs, files, links

def enumerate2(sequence):
    length = len(sequence)
    for count, value in enumerate(sequence):
        yield count, count - length, value

if __name__ == '__main__':
    main()

Puede reconocer la siguiente documentación del comando TREE en el terminal de Windows:

Graphically displays the folder structure of a drive or path.

TREE [drive:][path] [/F] [/A]

   /F   Display the names of the files in each folder.
   /A   Use ASCII instead of extended characters.

5

Recorrido recursivo a través de un directorio donde obtienes TODOS los archivos de todos los directorios del directorio actual y obtienes TODOS los directorios del directorio actual, porque los códigos anteriores no tienen simplicidad (en mi humilde opinión):

for root, dirs, files in os.walk(rootFolderPath):
    for filename in files:
        doSomethingWithFile(os.path.join(root, filename))
    for dirname in dirs:
        doSomewthingWithDir(os.path.join(root, dirname))

3
La respuesta más útil. Tenga en cuenta que os.path.join(root, filename)proporciona la ruta completa al archivo, incluso si el archivo está anidado en varios directorios.
clw

4

Esto lo hace para los nombres de carpetas:

def printFolderName(init_indent, rootFolder):
    fname = rootFolder.split(os.sep)[-1]
    root_levels = rootFolder.count(os.sep)
    # os.walk treats dirs breadth-first, but files depth-first (go figure)
    for root, dirs, files in os.walk(rootFolder):
        # print the directories below the root
        levels = root.count(os.sep) - root_levels
        indent = ' '*(levels*2)
        print init_indent + indent + root.split(os.sep)[-1]

3
#!/usr/bin/python

import os 

def tracing(a):
    global i>
    for item in os.listdir(a):
        if os.path.isfile(item):
            print i + item 
        else:
            print i + item 
            i+=i
            tracing(item)

i = "---"
tracing(".")

1

Dado un nombre de carpeta, recorre toda su jerarquía de forma recursiva.

#! /usr/local/bin/python3
# findLargeFiles.py - given a folder name, walk through its entire hierarchy
#                   - print folders and files within each folder

import os

def recursive_walk(folder):
    for folderName, subfolders, filenames in os.walk(folder):
        if subfolders:
            for subfolder in subfolders:
                recursive_walk(subfolder)
        print('\nFolder: ' + folderName + '\n')
        for filename in filenames:
            print(filename + '\n')

recursive_walk('/name/of/folder')

44
No es necesario llamar a os.walk de forma recursiva, ya que aplana la recursividad. Es por eso que devuelve el argumento folderName.
gwideman

1

Seria la mejor manera

def traverse_dir_recur(dir):
    import os
    l = os.listdir(dir)
    for d in l:
        if os.path.isdir(dir + d):
            traverse_dir_recur(dir+  d +"/")
        else:
            print(dir + d)

No funciona para mí en Python3. Supongo que el error está en dir + d, lo que podría concat sin separador de directorio. Probablemente sea mejor usar os.path.joinpara concatenar directorios con nombres de archivos
Zvika

0

Intenta esto; fácil

 #!/usr/bin/python
 import os
 # Creating an empty list that will contain the already traversed paths
 donePaths = []
 def direct(path):
       for paths,dirs,files in os.walk(path):
             if paths not in donePaths:
                    count = paths.count('/')
                    if files:
                          for ele1 in files:
                                print '---------' * (count), ele1
                    if dirs:
                          for ele2 in dirs:
                                print '---------' * (count), ele2
                                absPath = os.path.join(paths,ele2)
              # recursively calling the direct function on each directory
                                direct(absPath)
                   # adding the paths to the list that got traversed 
                                donePaths.append(absPath)

 path = raw_input("Enter any path to get the following Dir Tree ...\n")
 direct(path)

======== SALIDA a continuación ========

 /home/test
 ------------------ b.txt
 ------------------ a.txt
 ------------------ a
 --------------------------- a1.txt
 ------------------ b
 --------------------------- b1.txt
 --------------------------- b2.txt
 --------------------------- cde
 ------------------------------------ cde.txt
 ------------------------------------ cdeDir
 --------------------------------------------- cdeDir.txt
 ------------------ c
 --------------------------- c.txt
 --------------------------- c1
 ------------------------------------ c1.txt
 ------------------------------------ c2.txt

¿Cuál es el objetivo de la verificación de rutas ya atravesadas? Si se trata de detectar bucles causados ​​por enlaces, os.walk aparentemente por defecto no sigue los enlaces. ¿Hay alguna otra situación?
gwideman

0

Prueba esto:

import os
root_name = next(os.walk("."))[0]
dir_names = next(os.walk("."))[1]
file_names = next(os.walk("."))[2]

Aquí estoy asumiendo tu camino como "." en el que el directorio raíz y otros directorios están ahí. Entonces, básicamente, solo estamos iterando en todo el árbol usando la llamada next (), ya que nuestro os.walk es solo una función generativa. Al hacer esto, podemos guardar todos los nombres de Directorio y de archivo en dir_names y file_names respectivamente.


0

También puede recorrer recursivamente una carpeta y enumerar todos sus contenidos usando pathlib.Path ()

from pathlib import Path


def check_out_path(target_path, level=0):
    """"
    This function recursively prints all contents of a pathlib.Path object
    """
    def print_indented(folder, level):
        print('\t' * level + folder)

    print_indented(target_path.name, level)
    for file in target_path.iterdir():
        if file.is_dir():
            check_out_path(file, level+1)
        else:
            print_indented(file.name, level+1)


my_path = Path(r'C:\example folder')
check_out_path(my_path)

Salida:

example folder
    folder
        textfile3.txt
    textfile1.txt
    textfile2.txt

-3
import os

os.chdir('/your/working/path/')
dir = os.getcwd()
list = sorted(os.listdir(dir))
marks = ""

for s_list in list:
    print marks + s_list
    marks += "---"
    tree_list = sorted(os.listdir(dir + "/" + s_list))
    for i in tree_list:
        print marks + i

Esto no parece que atraviese todo el árbol.
Todos los trabajadores son esenciales
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.