【问题标题】:List directory tree structure in python?在python中列出目录树结构?
【发布时间】:2012-04-01 10:19:00
【问题描述】:

我知道我们可以使用os.walk() 列出所有子目录或目录中的所有文件。但是,我想列出完整的目录树内容:

- Subdirectory 1:
   - file11
   - file12
   - Sub-sub-directory 11:
         - file111
         - file112
- Subdirectory 2:
    - file21
    - sub-sub-directory 21
    - sub-sub-directory 22    
        - sub-sub-sub-directory 221
            - file 2211

如何在 Python 中最好地实现这一点?

【问题讨论】:

    标签: python traversal directory-structure


    【解决方案1】:

    这里有一个函数可以用格式化来做到这一点:

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

    【讨论】:

    • 效果很好,谢谢。尽管大多数人都知道,但仍然是为了让 Python 新手受益 - 请注意,您需要在最后调用该函数(假设是 windows),因此您可以在末尾添加一个新行,内容为 list_files ("D: \\")
    • 在 python3 上运行良好。但是在 python2 上,ValueError: zero length field name in format 被抛出。
    • 如果 startpath 在 root 内重复,它不会替换每次出现吗?更改为 root.replace(startpath, '', 1) 应该可以解决这个问题
    【解决方案2】:

    类似于上面的答案,但对于 python3,可以说是可读且可以扩展的:

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

    示例用法:

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

    示例输出:

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

    注意事项

    • 这使用递归。它将在真正文件夹树上提出RecursionError
    • 懒惰地评估树。它应该在真正 wide 文件夹树上表现良好。但是,给定文件夹的直接子级不会被延迟评估。

    编辑:

    • 额外奖励!过滤路径的标准回调。

    【讨论】:

    • 不错的工具,你有一个关于如何使用标准来排除文件夹名称的简单示例吗?
    • 这正是我想要的。非常感谢!
    • DisplayablePath.make_tree(Path('doc'), criteria=lambda path: True if path.name not in ('.git', '__pycache__') else False)) 是过滤掉不需要的路径的示例。
    【解决方案3】:

    在 Python 中列出目录树结构?

    我们通常更喜欢只使用 GNU 树,但我们并不总是在每个系统上都有tree,有时可以使用 Python 3。一个好的答案可以很容易地复制粘贴,而不是要求 GNU tree

    tree 的输出如下所示:

    $ tree
    .
    ├── package
    │   ├── __init__.py
    │   ├── __main__.py
    │   ├── subpackage
    │   │   ├── __init__.py
    │   │   ├── __main__.py
    │   │   └── module.py
    │   └── subpackage2
    │       ├── __init__.py
    │       ├── __main__.py
    │       └── module2.py
    └── package2
        └── __init__.py
    
    4 directories, 9 files
    

    我在我称为pyscratch 的目录下的主目录中创建了上述目录结构。

    我在这里也看到了接近这种输出的其他答案,但我认为我们可以做得更好,使用更简单、更现代的代码和惰性评估方法。

    Python 中的树

    首先,让我们使用一个示例

    • 使用 Python 3 Path 对象
    • 使用yieldyield from 表达式(用于创建生成器函数)
    • 使用递归实现优雅简洁
    • 使用 cmets 和一些类型注释来提高清晰度
    from pathlib import Path
    
    # prefix components:
    space =  '    '
    branch = '│   '
    # pointers:
    tee =    '├── '
    last =   '└── '
    
    
    def tree(dir_path: Path, prefix: str=''):
        """A recursive generator, given a directory Path object
        will yield a visual tree structure line by line
        with each line prefixed by the same characters
        """    
        contents = list(dir_path.iterdir())
        # contents each get pointers that are ├── with a final └── :
        pointers = [tee] * (len(contents) - 1) + [last]
        for pointer, path in zip(pointers, contents):
            yield prefix + pointer + path.name
            if path.is_dir(): # extend the prefix and recurse:
                extension = branch if pointer == tee else space 
                # i.e. space because last, └── , above so no more |
                yield from tree(path, prefix=prefix+extension)
    

    现在:

    for line in tree(Path.home() / 'pyscratch'):
        print(line)
    

    打印:

    ├── package
    │   ├── __init__.py
    │   ├── __main__.py
    │   ├── subpackage
    │   │   ├── __init__.py
    │   │   ├── __main__.py
    │   │   └── module.py
    │   └── subpackage2
    │       ├── __init__.py
    │       ├── __main__.py
    │       └── module2.py
    └── package2
        └── __init__.py
    

    我们确实需要将每个目录具体化为一个列表,因为我们需要知道它有多长,但之后我们将列表丢弃。对于深度和广泛的递归,这应该足够懒惰。

    上面的代码和 cmets 应该足以完全理解我们在这里所做的事情,但如果需要,请随时使用调试器逐步完成它,以便更好地对其进行调试。

    更多功能

    现在 GNU tree 为我们提供了一些我希望该功能具有的有用功能:

    • 首先打印主题目录名称(自动打印,我们的不会)
    • 打印n directories, m files的计数
    • 限制递归的选项,-L level
    • 仅限目录的选项,-d

    此外,当有一棵巨大的树时,限制迭代(例如使用islice)以避免将您的解释器锁定在文本中很有用,因为在某些时候输出变得过于冗长而无用。默认情况下,我们可以将其设置为任意高 - 比如1000

    那么让我们删除之前的 cmets 并填写这个功能:

    from pathlib import Path
    from itertools import islice
    
    space =  '    '
    branch = '│   '
    tee =    '├── '
    last =   '└── '
    
    def tree(dir_path: Path, level: int=-1, limit_to_directories: bool=False,
             length_limit: int=1000):
        """Given a directory Path object print a visual tree structure"""
        dir_path = Path(dir_path) # accept string coerceable to Path
        files = 0
        directories = 0
        def inner(dir_path: Path, prefix: str='', level=-1):
            nonlocal files, directories
            if not level: 
                return # 0, stop iterating
            if limit_to_directories:
                contents = [d for d in dir_path.iterdir() if d.is_dir()]
            else: 
                contents = list(dir_path.iterdir())
            pointers = [tee] * (len(contents) - 1) + [last]
            for pointer, path in zip(pointers, contents):
                if path.is_dir():
                    yield prefix + pointer + path.name
                    directories += 1
                    extension = branch if pointer == tee else space 
                    yield from inner(path, prefix=prefix+extension, level=level-1)
                elif not limit_to_directories:
                    yield prefix + pointer + path.name
                    files += 1
        print(dir_path.name)
        iterator = inner(dir_path, level=level)
        for line in islice(iterator, length_limit):
            print(line)
        if next(iterator, None):
            print(f'... length_limit, {length_limit}, reached, counted:')
        print(f'\n{directories} directories' + (f', {files} files' if files else ''))
    

    现在我们可以得到与tree 相同的输出:

    tree(Path.home() / 'pyscratch')
    

    打印:

    pyscratch
    ├── package
    │   ├── __init__.py
    │   ├── __main__.py
    │   ├── subpackage
    │   │   ├── __init__.py
    │   │   ├── __main__.py
    │   │   └── module.py
    │   └── subpackage2
    │       ├── __init__.py
    │       ├── __main__.py
    │       └── module2.py
    └── package2
        └── __init__.py
    
    4 directories, 9 files
    

    我们可以限制级别:

    tree(Path.home() / 'pyscratch', level=2)
    

    打印:

    pyscratch
    ├── package
    │   ├── __init__.py
    │   ├── __main__.py
    │   ├── subpackage
    │   └── subpackage2
    └── package2
        └── __init__.py
    
    4 directories, 3 files
    

    我们可以限制输出到目录:

    tree(Path.home() / 'pyscratch', level=2, limit_to_directories=True)
    

    打印:

    pyscratch
    ├── package
    │   ├── subpackage
    │   └── subpackage2
    └── package2
    
    4 directories
    

    回顾

    回想起来,我们可以使用path.glob 进行匹配。我们也可以使用path.rglob 进行递归通配,但这需要重写。我们也可以使用itertools.tee,而不是具体化目录内容列表,但这可能会产生负面影响,并且可能会使代码更加复杂。

    欢迎评论!

    【讨论】:

    • 要打印代码行,在elif not limit_to_directories: 之后添加以下内容:info = prefix + pointer + path.name; try: with path.open('r') as f: n_lines = len(f.readlines()); loc = f' LOC: {n_lines}'; info += loc; except UnicodeDecodeError: pass; yield info 请参阅this link 以获得正确的空白。
    • 这正是我在代码中所需要的,并且教会了我一些新的 Python 技巧!我唯一要注意的是,如果limit_to_directories 为真,则需要过滤contents。否则,如果文件夹没有最后一个文件的目录,则无法正确绘制树。 if limit_to_directories: contents = [path for path in contents if path.is_dir()]
    • @hennign 谢谢,答案已更新,感谢反馈!
    • Python 都基于list(dir_path.iterdir()) 返回一个正确排序的自上而下的目录结构树。我在API for iterdir() 中看到没有这样的保证。请提供iterdir() 如何订购或保证提供所需订购的参考。
    • @ingyhere 我不知道你从哪里得到这个想法 - seems to use os.listdir() by default - which makes no guarantee of the order :“列表是任意顺序的,不包括特殊条目'。'和 '..' 即使它们存在于目录中。”
    【解决方案4】:

    无需缩进的解决方案:

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

    os.walk 已经完成了您正在寻找的自上而下、深度优先的步行。

    忽略目录列表可防止您提到的重叠。

    【讨论】:

    • python 说:NameError: name 'path' is not defined
    • @FrancescoMantovani "path" 是包含您要打印的目录的变量,即 r"C:\Users\username\Documents\path"
    【解决方案5】:

    我来这里是为了寻找同样的东西,并为我使用了 dhobbs 答案。作为感谢社区的一种方式,我添加了一些参数来写入文件,正如 akshay 所要求的那样,并且显示文件是可选的,因此它不是一个输出。还使缩进成为可选参数,以便您可以更改它,因为有些人喜欢它是 2 而其他人更喜欢 4。

    使用了不同的循环,因此不显示文件的循环不会在每次迭代时检查它是否必须。

    希望它对其他人有所帮助,因为 dhobbs 的回答对我有所帮助。非常感谢。

    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
    

    【讨论】:

    • 我觉得这个答案对已经接受的答案没有贡献。您唯一提供的是额外的绒毛代码来关闭功能或不在响应中。
    • 你的感觉是对的,@jason-heine。公认的答案已经足够好了,但是有些人问如何做这些绒毛的东西,我想给他们一些东西。如果您不想在 SO 中看到此内容,请投反对票或报告我的答案,我认为这不会造成伤害,但我可能错了。
    • 确实有用。非常感谢。我照原样使用它。
    【解决方案6】:

    有一个名为 seedir 的包(我创建的)用于执行此操作以及其他使用文件夹树图的操作:

    >>> import seedir as sd
    >>> sd.seedir('/path/to/some/path/or/package', style='emoji')
    ? package/
    ├─? __init__.py
    ├─? subpackage1/
    │ ├─? __init__.py
    │ ├─? moduleX.py
    │ └─? moduleY.py
    ├─? subpackage2/
    │ ├─? __init__.py
    │ └─? moduleZ.py
    └─? moduleA.py
    
    

    类似于 OP 使用的样式可以通过以下方式完成:

    >>> sd.seedir('/path/to/folder', style='spaces', indent=4, anystart='- ')
    - package/
        - __init__.py
        - subpackage1/
            - __init__.py
            - moduleX.py
            - moduleY.py
        - subpackage2/
            - __init__.py
            - moduleZ.py
        - moduleA.py
    
    

    【讨论】:

    • 可以导出为.png图片吗?
    • @israteneda 目前没有,但可以添加!
    • @Justaus3r 是的!
    【解决方案7】:

    基于这篇精彩的帖子

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

    这里是一个细化的行为,就像

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

    #!/usr/bin/env python2
    # -*- 编码:utf-8 -*-
    
    # 树.py
    #
    # 由道格·达姆斯撰写
    #
    # 打印命令行指定路径的树结构
    
    从操作系统导入列表目录,九月
    从 os.path 导入 abspath、basename、isdir
    从系统导入 argv
    
    def 树(目录,填充,print_files=False,isLast=False,isFirst=False):
        如果是第一:
            打印 padding.decode('utf8')[:-1].encode('utf8') + dir
        别的:
            如果是最后一个:
                打印 padding.decode('utf8')[:-1].encode('utf8') + '└── ' + basename(abspath(dir))
            别的:
                打印 padding.decode('utf8')[:-1].encode('utf8') + '├── ' + basename(abspath(dir))
        文件 = []
        如果打印文件:
            文件 = 列表目录(目录)
        别的:
            files = [x for x in listdir(dir) if isdir(dir + sep + x)]
        如果不是 isFirst:
            填充 = 填充 + ' '
        文件=排序(文件,键= lambda s:s.lower())
        计数 = 0
        最后 = len(文件) - 1
        对于我,枚举中的文件(文件):
            计数 += 1
            路径 = 目录 + sep + 文件
            isLast = i == 最后
            如果是目录(路径):
                如果计数 == len(文件):
                    如果是第一:
                        树(路径,填充,打印文件,isLast,假)
                    别的:
                        树(路径,填充 + '',print_files,isLast,False)
                别的:
                    树(路径,填充 + '│',print_files,isLast,False)
            别的:
                如果是最后一个:
                    打印填充 + '└── ' + 文件
                别的:
                    打印填充 + '├── ' + 文件
    
    默认用法():
        return '''用法:%s [-f]
    打印指定路径的树结构。
    选项:
    -f 打印文件和目录
    PATH 处理路径''' % basename(argv[0])
    
    定义主():
        如果 len(argv) == 1:
            打印用法()
        elif len(argv) == 2:
            # 只打印目录
            路径 = argv[1]
            如果是目录(路径):
                树(路径,'',假,假,真)
            别的:
                print 'ERROR: \'' + path + '\' 不是目录'
        elif len(argv) == 3 和 argv[1] == '-f':
            # 打印目录和文件
            路径 = argv[2]
            如果是目录(路径):
                树(路径,'',真,假,真)
            别的:
                print 'ERROR: \'' + path + '\' 不是目录'
        别的:
            打印用法()
    
    如果 __name__ == '__main__':
        主要的()
    
    
    

    【讨论】:

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

      如果有人感兴趣 - 该递归函数返回字典的嵌套结构。键是file system 名称(目录和文件),值是:

      • 目录的子字典
      • 文件字符串(见file_token

      在此示例中,指定文件的字符串为空。它们也可以是例如给定文件内容或其所有者信息或特权或任何不同于字典的对象。除非它是字典,否则在进一步的操作中很容易将其与“目录类型”区分开来。

      在文件系统中有这样的树:

      # 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
      

      结果将是:

      # 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': {}
      }
      

      如果你喜欢,我已经用这些东西创建了一个包(python 2 和 3)(还有一个很好的 pyfakefs 助手): https://pypi.org/project/fsforge/

      【讨论】:

      • 能否请您详细说明如何使用file_token 读取文件属性,例如filesize,谢谢!
      • 当然。将行 tree.update({f: file_token for f in files}) 更改为 tree.update({f: os.path.getsize(os.path.join(root, f)) for f in files})。然后可以删除定义file_token 的行。
      【解决方案9】:

      在上面的 dhobbs 回答 (https://stackoverflow.com/a/9728478/624597) 之上,这是一个将结果存储到文件的额外功能(我个人使用它来复制并粘贴到 FreeMind 以便对结构有一个很好的概述,因此我使用制表符代替空格进行缩进):

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

      【讨论】:

        【解决方案10】:

        只有在您的系统上安装了tree 时,此解决方案才有效。不过,我将把这个解决方案留在这里,以防它帮助别人。

        您可以告诉 tree 将树结构输出为 XML (tree -X) 或 JSON (tree -J)。 JSON 当然可以直接用 python 解析,XML 可以很容易地用lxml 读取。

        以如下目录结构为例:

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

        【讨论】:

          【解决方案11】:

          你可以执行Linux shell的'tree'命令。

          安装:

             ~$sudo apt install tree
          

          在python中使用

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

          例子:

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

          这使您的结构更清晰,视觉上更全面且易于键入。

          【讨论】:

          【解决方案12】:

          也许比@ellockie(也许)更快

          导入操作系统 def file_writer(文本): 使用 open("folder_structure.txt","a") 作为 f_output: f_output.write(文本) def list_files(startpath): 对于 os.walk(startpath) 中的根目录、目录和文件: level = root.replace(startpath, '').count(os.sep) 缩进 = '\t' * 1 * (级别) output_string = '{}{}/ \n'.format(indent, os.path.basename(root)) 文件编写器(输出字符串) subindent = '\t' * 1 * (level + 1) output_string = '%s %s \n' %(subindent,[f for f in files]) file_writer(''.join(output_string)) list_files("/")

          测试结果如下截图:

          【讨论】:

            【解决方案13】:

            在这里您可以找到输出如下的代码: https://stackoverflow.com/a/56622847/6671330

            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
            

            【讨论】:

              【解决方案14】:

              对于那些仍在寻找答案的人。这是一种在字典中获取路径的递归方法。

              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}
              

              【讨论】:

                【解决方案15】:

                @dhobbs's answer 太棒了!

                但只需更改即可轻松获取关卡信息

                def print_list_dir(dir):
                    print("=" * 64)
                    print("[PRINT LIST DIR] %s" % dir)
                    print("=" * 64)
                    for root, dirs, files in os.walk(dir):
                        level = root.replace(dir, '').count(os.sep)
                        indent = '| ' * level
                        print('{}{} \\'.format(indent, os.path.basename(root)))
                        subindent = '| ' * (level + 1)
                        for f in files:
                            print('{}{}'.format(subindent, f))
                    print("=" * 64)
                

                和输出类似

                ================================================================
                [PRINT LIST DIR] ./
                ================================================================
                 \
                | os_name.py
                | json_loads.py
                | linspace_python.py
                | list_file.py
                | to_gson_format.py
                | type_convert_test.py
                | in_and_replace_test.py
                | online_log.py
                | padding_and_clipping.py
                | str_tuple.py
                | set_test.py
                | script_name.py
                | word_count.py
                | get14.py
                | np_test2.py
                ================================================================
                

                你可以通过|计数获得等级!

                【讨论】:

                  【解决方案16】:

                  又一个tree() 函数,有一些我觉得有用的功能:

                  • 设置max_files 限制每个目录的文件数
                  • 设置max_level限制深度
                  • 设置sort_by 对文件和目录进行排序,例如sort_by=os.path.getmtime 按最后修改日期排序。默认是按名称排序。请注意,目录始终显示在文件之前。
                  • 设置indent 设置每个缩进级别的空格数,默认为4。
                  from pathlib import Path
                  
                  def tree(path, *, indent=4, max_files=None, sort_by=None, level=0, max_level=None):
                      path = Path(path)
                      if not path.is_dir():
                          return
                      indent_str = " " * indent * level
                      print(f"{indent_str}{path.name}/")
                      sub_indent_str = " " * indent * (level + 1)
                      dir_content = list(path.iterdir())
                      subdirs = [filepath for filepath in dir_content if filepath.is_dir()]
                      files = [filepath for filepath in dir_content if not filepath in subdirs]
                      if max_level is not None and level < max_level:
                          for subdir in sorted(subdirs, key=sort_by):
                              tree(subdir, indent=indent, max_files=max_files, sort_by=sort_by,
                                   level=level + 1, max_level=max_level)
                      for idx, filepath in enumerate(sorted(files, key=sort_by)):
                          if max_files is not None and idx >= max_files:
                              print(f"{sub_indent_str}...")
                              break
                          print(f"{sub_indent_str}{filepath.name}")
                  

                  示例输出:

                  some_path/
                      some_subdir/
                      another_subdir/
                          foo.txt
                          bar.txt
                      big_subdir/
                          a00001.txt
                          a00002.txt
                          a00003.txt
                          ...
                      deeply_nested/
                          max_depth1/
                          max_depth2/
                  

                  【讨论】:

                    猜你喜欢
                    • 2014-02-02
                    • 2022-06-15
                    • 2019-06-26
                    • 2019-04-23
                    • 2021-02-17
                    • 2014-05-01
                    • 2010-09-12
                    • 2013-12-15
                    相关资源
                    最近更新 更多