列出 Python 中的目录树结构?

我知道我们可以使用 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 中最好地实现这一点?

212086 次浏览

没有凹痕的解决方案:

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

Os.walk 已经完成了你所寻找的自上而下、深度优先的步行。

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

这里有一个函数用于格式化:

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

我来这里也是为了找同样的东西,我用 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

基于这篇精彩的文章

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

这里有一个完美的表现

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

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


# tree.py
#
# Written by Doug Dahms
#
# Prints the tree structure for the path specified on the command line


from os import listdir, sep
from os.path import abspath, basename, isdir
from sys import argv


def tree(dir, padding, print_files=False, isLast=False, isFirst=False):
if isFirst:
print padding.decode('utf8')[:-1].encode('utf8') + dir
else:
if isLast:
print padding.decode('utf8')[:-1].encode('utf8') + '└── ' + basename(abspath(dir))
else:
print padding.decode('utf8')[:-1].encode('utf8') + '├── ' + basename(abspath(dir))
files = []
if print_files:
files = listdir(dir)
else:
files = [x for x in listdir(dir) if isdir(dir + sep + x)]
if not isFirst:
padding = padding + '   '
files = sorted(files, key=lambda s: s.lower())
count = 0
last = len(files) - 1
for i, file in enumerate(files):
count += 1
path = dir + sep + file
isLast = i == last
if isdir(path):
if count == len(files):
if isFirst:
tree(path, padding, print_files, isLast, False)
else:
tree(path, padding + ' ', print_files, isLast, False)
else:
tree(path, padding + '│', print_files, isLast, False)
else:
if isLast:
print padding + '└── ' + file
else:
print padding + '├── ' + file


def usage():
return '''Usage: %s [-f]
Print tree structure of path specified.
Options:
-f      Print files as well as directories
PATH    Path to process''' % basename(argv[0])


def main():
if len(argv) == 1:
print usage()
elif len(argv) == 2:
# print just directories
path = argv[1]
if isdir(path):
tree(path, '', False, False, True)
else:
print 'ERROR: \'' + path + '\' is not a directory'
elif len(argv) == 3 and argv[1] == '-f':
# print directories and files
path = argv[2]
if isdir(path):
tree(path, '', True, False, True)
else:
print 'ERROR: \'' + path + '\' is not a directory'
else:
print usage()


if __name__ == '__main__':
main()




除了上面的 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(".")

也许比@ellockie 快(也许)

import os
def file_writer(text):
with open("folder_structure.txt","a") as f_output:
f_output.write(text)
def list_files(startpath):




for root, dirs, files in os.walk(startpath):
level = root.replace(startpath, '').count(os.sep)
indent = '\t' * 1 * (level)
output_string = '{}{}/ \n'.format(indent, os.path.basename(root))
file_writer(output_string)
subindent = '\t' * 1 * (level + 1)
output_string = '%s %s \n' %(subindent,[f for f in files])
file_writer(''.join(output_string))




list_files("/")


测试结果截图如下:

enter image description here

您可以执行 Linux shell 的“ tree”命令。

安装:

   ~$sudo apt install tree

在 python 中使用

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

例如:

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

这使您的结构更清晰,并且在视觉上更全面,更容易输入。

类似于上面的答案,但是对于 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'),
criteria=is_not_hidden
)
for path in paths:
print(path.displayable())


# With a criteria (skip hidden files)
def is_not_hidden(path):
return not path.name.startswith(".")


paths = DisplayablePath.make_tree(Path('doc'), criteria=is_not_hidden)
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

笔记

  • 这使用递归。它会在真正的 很深文件夹树上产生一个 递归错误
  • 对树进行惰性计算。它在真正的 很宽文件夹树上应该表现良好。但是,不会懒惰地计算给定文件夹的直接子级。

编辑:

  • 增加了筛选路径的奖励! 标准回调。
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)

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

在文件系统中有这样一棵树:

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

如果你喜欢,我已经用这些东西创建了一个包(python2 & 3)(还有一个不错的 pyfakefs助手) : Https://pypi.org/project/fsforge/

只有在系统上安装了 tree时,此解决方案才能正常工作。然而,我把这个解决方案留在这里,以防它帮助其他人。

您可以告诉 tree 以 XML (tree -X)或 JSON (tree -J)的形式输出树结构。当然,可以用 python 直接解析 JSON,也可以用 lxml轻松地读取 XML。

以下面的目录结构为例:

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

在这里您可以找到如下输出的代码: 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

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

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}

列出 Python 中的目录树结构?

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

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

我在我的 home 目录下创建了上面的目录结构,我称之为 pyscratch

我还在这里看到了其他一些解决方法,但我认为我们可以做得更好,使用更简单、更现代的代码和懒惰地评估方法。

巨蟒中的树

首先,让我们用一个例子

  • 使用 Python 3 Path对象
  • 使用 yieldyield from表达式(创建生成器函数)
  • 使用递归实现优雅的简单性
  • 使用注释和一些类型注释来增加清晰度
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

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

上面的代码和注释应该足以完全理解我们在这里做什么,但是如果需要的话,可以使用调试器逐步完成它,以便更好地理解它。

更多功能

现在 GNU tree给我们提供了一些有用的特性,我希望这个函数能有这些特性:

  • 首先打印主题目录名称(这样做是自动的,而我们的不是)
  • 打印 n directories, m files的计数
  • 限制递归的选项
  • 选项限制到只有目录,-d

此外,当有一个巨大的树时,限制迭代是有用的(例如使用 islice) ,以避免用文本锁定您的解释器,因为在某些时候输出变得过于冗长而没有用处。我们可以在默认情况下任意调高这个值——比如说 1000

因此,让我们删除前面的评论,并填写以下功能:

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进行递归 globbing,但是这需要重写。我们也可以使用 itertools.tee而不是具体化目录内容列表,但是这可能会产生负面的折衷,并且可能会使代码更加复杂。

欢迎评论!

有一个软件包(我创建的)称为 种族歧视,用于处理这个和其他文件夹树图表的事情:

>>> import seedir as sd
>>> sd.seedir('/path/to/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/package', style='spaces', indent=4, anystart='- ')
- package/
- __init__.py
- subpackage1/
- __init__.py
- moduleX.py
- moduleY.py
- subpackage2/
- __init__.py
- moduleZ.py
- moduleA.py



还有一个命令行界面,例如:

seedir -y emoji

有关所有选项,请参见

seedir --help

您也可以像前面注释的那样执行 python -m seedir.command_line,但是 pip安装应该只使用命令 seedir提供入口点。

这是另一个 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/

Python 2 & Python 3: 我在这里看到了一些比我自己的更有良心的答案,然而,对于我的应用程序,我没有访问它们所依赖的库的权限。这是我完成任务的方法。另外,对于我的应用程序,我需要知道每个文件的绝对路径,所以我将它与文件名一起打印出来。

#!/usr/bin/env python
# -*- coding: utf_8 -*-
import os


PIPE = "│"
ELBOW = "└──"
TEE = "├──"
PIPE_PREFIX = "│   "
SPACE_PREFIX = "    "




def list_files(startpath):


for root, dirs, files in os.walk(startpath):
break
    

tree = []
for i, file in enumerate(files):
if i == len(files)-1 and len(dirs) == 0:
joint = ELBOW
else:
joint = TEE
tree.append('{} {} : {}'.format(joint, file, os.path.join(root, file)))
    

for i, dir in enumerate(dirs):
if i == len(dirs)-1:
joint = ELBOW
space = SPACE_PREFIX
else:
joint = TEE
space = PIPE_PREFIX
        

tree.append('{} {}/'.format(joint, dir))
branches = list_files(os.path.join(root,dir))
for branch in branches:
tree.append('{}{}'.format(space, branch))


return tree


if __name__ == '__main__':
# Obtain top level directory path
cwd = os.getcwd()
tree = list_files(cwd)
    

string = '../{}/\n'.format(os.path.basename(cwd))
for t in tree:
string += '{}\n'.format(t)
string = string.replace('\n', '\n   ')
print(string)

该脚本的输出是:

../TEST_DIR/
├── test.txt : /usr/scripts/TEST_DIR/test.txt
├── a/
│   ├── 1.txt : /usr/scripts/TEST_DIR/a/1.txt
│   ├── 2.py : /usr/scripts/TEST_DIR/a/2.py
│   └── 3.bit : /usr/scripts/TEST_DIR/a/3.bit
├── b/
│   ├── bb/
│   │   ├── 1.txt : /usr/scripts/TEST_DIR/b/bb/1.txt
│   │   ├── 2.py : /usr/scripts/TEST_DIR/b/bb/2.py
│   │   ├── 3.bit : /usr/scripts/TEST_DIR/b/bb/3.bit
│   │   └── bb_copy/
│   │       ├── 1.txt : /usr/scripts/TEST_DIR/b/bb/bb_copy/1.txt
│   │       ├── 2.py : /usr/scripts/TEST_DIR/b/bb/bb_copy/2.py
│   │       ├── 3.bit : /usr/scripts/TEST_DIR/b/bb/bb_copy/3.bit
│   │       └── bb_copy/
│   │           ├── 1.txt : /usr/scripts/TEST_DIR/b/bb/bb_copy/bb_copy/1.txt
│   │           ├── 2.py : /usr/scripts/TEST_DIR/b/bb/bb_copy/bb_copy/2.py
│   │           └── 3.bit : /usr/scripts/TEST_DIR/b/bb/bb_copy/bb_copy/3.bit
│   └── bb_copy/
│       ├── 1.txt : /usr/scripts/TEST_DIR/b/bb_copy/1.txt
│       ├── 2.py : /usr/scripts/TEST_DIR/b/bb_copy/2.py
│       └── 3.bit : /usr/scripts/TEST_DIR/b/bb_copy/3.bit
└── c/

如果有任何技巧可以使这个脚本更加流线型、良心和健壮,我将不胜感激。