Używanie os.walk () do rekurencyjnego przechodzenia po katalogach w Pythonie


151

Chcę przejść z katalogu głównego do wszystkich innych katalogów i wydrukować to samo.

Oto mój kod:

#!/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 ""

A oto moje 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

Powyżej .i./packagedemo są katalogami.

Jednak muszę wydrukować O / P w następujący sposób:

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

Powyżej, Ai Bsą katalogi, a reszta to pliki.


6
Chciałbym tutaj dodać ten mały post o sile Pythona: >>> print 2 * '-' ----
Nitaai

Odpowiedzi:


228

To da pożądany rezultat

#!/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)

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

9
@Ajay bądź paranoikiem i zawsze rób, os.walk(u".")ponieważ ścieżki mogą być w Unicode.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

3
Jeszcze lepiej,os.path.curdir
Jir

Używałem os.path.walkprzez jakiś czas, więc os.walkjest dla mnie nowy! Fajna fasola.
Tom

@Semprini co jest basepathrówne w Twoim kodzie?
stelios

23

Spróbuj tego:

#!/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))

otrzymasz to:

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

Cześć, naprawdę uwielbiam twój skrypt, ale jest on trochę zbyt skomplikowany dla projektu, nad którym pracuję. Czy jest jakaś szansa, żebym mógł go mieć jako jedną małą funkcję, z obecnym tylko argumentem -r?
jeff_h,

jak wydrukować to w formacie .txt? Próbowałem, print(FileTreeMaker().make(args),file=tree)ale daje mi to'charmap' codec can't encode characters in position 17-21: character maps to <undefined>
Luis Felipe

co oznacza idc
głosy

Napisałem też coś podobnego os.listdir(). Twój jest o wiele lepszy; Nie mogłem poprawnie uzyskać rekursji, działała tylko na 2 lub 3 warstwach. W końcu zdecydowałem się spróbować ponownie od zera os.walk(), co moim zdaniem byłoby o wiele bardziej odpowiednie. Dziwię się, że w ogóle go tu nie użyłeś.
głosy

11

W ospakiecie są do tego bardziej odpowiednie funkcje . Ale jeśli musisz użyć os.walk, oto co wymyśliłem

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)

wynik:

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

5
Więc jakie są bardziej odpowiednie funkcje? (w 3.5, jeśli to ma znaczenie)
Al Lelopath

Przepraszam, nie ma szans, żeby sobie przypomnieć, co miałem na myśli. Możliwe, że miałem na myśli, os.listdirale rozwiązanie @ ajay to przebija.
zaquest

5

Możesz użyć os.walki jest to prawdopodobnie najłatwiejsze rozwiązanie, ale oto inny pomysł do zbadania:

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()

Następującą dokumentację można rozpoznać po poleceniu TREE w terminalu systemu 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

Rekurencyjne przechodzenie przez katalog, w którym otrzymujesz WSZYSTKIE pliki ze wszystkich katalogów w bieżącym katalogu i WSZYSTKIE katalogi z bieżącego katalogu - ponieważ powyższe kody nie mają prostoty (imho):

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
Najbardziej pomocna odpowiedź. Zauważ, że os.path.join(root, filename)podaje pełną ścieżkę do pliku, nawet jeśli plik jest zagnieżdżony w kilku katalogach.
clw

4

Robi to dla nazw folderów:

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

Mając nazwę folderu, przejdź rekurencyjnie przez całą jego hierarchię.

#! /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')

4
Nie ma potrzeby rekurencyjnego wywoływania os.walk, ponieważ już spłaszcza rekursję. Dlatego zwraca argument nazwa_folderu.
gwideman

1

Byłby to najlepszy sposób

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)

Nie działa dla mnie w Python3. Zakładam, że błąd tkwi w dir + d, co może łączyć je bez separatora katalogów. Prawdopodobnie lepiej jest używać os.path.joindo łączenia katalogów z nazwami plików
Zvika

0

Spróbuj tego; Łatwy

 #!/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)

======== WYJŚCIE poniżej ========

 /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

Jaki jest cel sprawdzania już przebytych ścieżek? Jeśli ma to na celu wykrycie pętli spowodowanych przez łącza, os.walk najwyraźniej domyślnie nie podąża za linkami. Czy jest jakaś inna sytuacja?
gwideman

0

Spróbuj tego:

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

Tutaj przyjmuję twoją ścieżkę jako „”. w którym znajduje się root_file i inne katalogi. Tak więc, w zasadzie po prostu iterujemy po drzewie używając wywołania next (), ponieważ nasz os.walk jest tylko funkcją generującą. W ten sposób możemy zapisać wszystkie nazwy katalogów i plików odpowiednio w nazwach_katalogów i nazwach_plików.


0

Możesz również rekurencyjnie przejść przez folder i wyświetlić całą jego zawartość za pomocą 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)

Wynik:

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

To nie wygląda na to, że przechodzi przez całe drzewo.
Wszyscy pracownicy są niezbędni
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.