【问题标题】:Using os.walk() to recursively traverse directories in Python在 Python 中使用 os.walk() 递归遍历目录
【发布时间】:2023-01-09 20:20:33
【问题描述】:

我想从根目录导航到其中的所有其他目录并打印相同的内容。

这是我的代码:

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

这是我的 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

上面,../packagedemo是目录。

但是,我需要按以下方式打印 O/P:

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

上面AB是目录,其余是文件。

【问题讨论】:

  • 我想在这里添加这篇关于 python 强大功能的小帖子: >>> print 2 * '--' ----

标签: python os.walk


【解决方案1】:

这会给你想要的结果

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

【讨论】:

  • path = os.path.relpath(root, basepath).split(os.sep)
  • @Ajay 是偏执狂,总是做os.walk(u"."),因为路径可以是 Unicode。
  • 更好的是,os.path.curdir
  • 我已经使用 os.path.walk 一段时间了,所以 os.walk 对我来说是新的!酷豆。
  • @Semprini basepath 在您的代码中等于什么?
【解决方案2】:

尝试这个:

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

你会得到这个:

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

【讨论】:

  • 你好,我真的很喜欢你的脚本,但它对于我正在从事的项目来说有点太复杂了,我有没有可能将它作为一个小函数,只提供 -r 参数?
  • 如何在 .txt 中打印它?我试过 print(FileTreeMaker().make(args),file=tree) 但它给了我 'charmap' codec can't encode characters in position 17-21: character maps to &lt;undefined&gt;
  • idc是什么意思
  • 我也用 os.listdir() 写了类似的东西。你的好多了;我无法正确地进行递归,它只能在 2 或 3 层深处工作。最后我决定用os.walk() 从头开始​​再试一次,我认为这会更合适。我很惊讶你根本没有在这里使用它。
【解决方案3】:

递归遍历一个目录,在该目录中,您从当前目录中的所有目录中获取所有文件,然后从当前目录中获取所有目录 - 因为上面的代码并不简单(恕我直言):

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

【讨论】:

  • 最有帮助的答案。请注意,os.path.join(root, filename) 给出了文件的完整路径,即使文件嵌套在多个目录中也是如此。
【解决方案4】:

os 包中有更合适的功能。但是如果你必须使用os.walk,这就是我想出的

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)

输出:

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

【讨论】:

  • 那么有哪些比较合适的功能呢? (如果重要的话,在 3.5 中)
  • 对不起,没机会记住我的意思了。有可能我的意思是os.listdir,但@ajay 的解决方案胜过它。
【解决方案5】:

您还可以递归遍历文件夹并使用 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('	' * 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)

输出:

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

【讨论】:

  • 我喜欢这个,因为它使用了pathlib。谢谢
【解决方案6】:

您可以使用os.walk,这可能是最简单的解决方案,但这里还有另一个需要探索的想法:

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

您可能会从 Windows 终端中的 TREE 命令中识别出以下文档:

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.

【讨论】:

    【解决方案7】:

    这是针对文件夹名称执行的:

    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]
    

    【讨论】:

      【解决方案8】:
      #!/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(".")
      

      【讨论】:

        【解决方案9】:

        给定文件夹名称,递归遍历其整个层次结构。

        #! /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('
        Folder: ' + folderName + '
        ')
                for filename in filenames:
                    print(filename + '
        ')
        
        recursive_walk('/name/of/folder')
        

        【讨论】:

        • 无需递归调用 os.walk,因为它已经使递归变平。这就是它返回 folderName 参数的原因。
        【解决方案10】:

        会是最好的办法

        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)
        

        【讨论】:

        • 在 Python3 中不适合我。我假设错误在 dir + d 中,这可能会在没有目录分隔符的情况下连接它们。最好使用 os.path.join 将目录与文件名连接起来
        【解决方案11】:

        尝试这个:

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

        在这里,我假设您的路径为“。”其中有 root_file 和其他目录。 所以,基本上我们只是通过使用 next() 调用遍历整个树,因为我们的 os.walk 只是生成函数。 通过这样做,我们可以将所有目录和文件名分别保存在 dir_names 和 file_names 中。

        【讨论】:

          【解决方案12】:

          试试这个;简单的

           #!/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 ...
          ")
           direct(path)
          

          ========下面的输出========

           /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
          

          【讨论】:

          • 检查已经遍历的路径有什么意义?如果要检测由链接引起的循环,os.walk 显然默认为不跟踪链接。还有其他情况吗?
          【解决方案13】:

          假设您有一个带有子目录的任意父目录:

          /home/parent_dir
          ├── 0_N
          ├── 1_M
          ├── 2_P
          ├── 3_R
          └── 4_T
          

          这是你可以做的来估计近似每个子目录中的 #files 百分比分布相对于父目录中的 #files 总数:

          from os import listdir as osl
          from os import walk as osw
          from os.path import join as osj
          
          def subdir_summary(parent_dir):
              parent_dir_len = sum([len(files) for _, _, files in osw(parent_dir)])
              print(f"Total files in parent: {parent_dir_len}")
              for subdir in sorted(osl(parent_dir)):
                  subdir_files_len = len(osl(osj(parent_dir, subdir)))
                  print(subdir, subdir_files_len, f"{int(100*(subdir_files_len / parent_dir_len))}%")
          
          subdir_summary("/home/parent_dir")
          

          它将在终端中打印如下:

          Total files in parent: 5876
          0_N 3254 55%
          1_M 509 8%
          2_P 1187 20%
          3_R 594 10%
          4_T 332 5%
          

          【讨论】:

            【解决方案14】:
            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
            

            【讨论】:

            • 这看起来不像是遍历整棵树。