python目录树_用Python 编写一个目录树插件

Linux下有一个命令叫做tree(其实Windows也自带了一个类似的),可以生成一个目录的树形结构。

这个命令在学习软件架构,撰写文档方面挺有帮助的。今天,我们来用Python实现一个类似的函数,然后加一些包装,做成一个SublimeText3的插件。

我们插件在条目的排列上要支持一下选项Directory First

Directory Only

File First

Ordered

还要支持缩进级别参数、是否显示隐藏文件、是否显示文件尺寸(或文件夹中条目的个数),支持在条目间插入空行等待。

我们使用4个Unicode的制表符"│","├","└"和"─"来使生成的目录树看上去更美观一些。

我们使用Python的类来接受这些参数

class Tree():

mode_descriptions = {

'df': 'Directory First',

'do': 'Directory Only',

'ff': 'File First',

'od': 'Ordered'

}

def __init__(self, path, indent=4, mode='ff', layer=0,

sparse=True, dtail='/', show_hidden=False, show_size=False,

show_absolute_path_of_rootdir=False):

indent = min(max(indent, 1), 8)

self.sparse = sparse

self.dtail = dtail

self.layer = layer if layer > 0 else 65535

self.indent_space = ' ' * indent

self.down_space = '│' + ' ' * (indent - 1)

self.vert_horiz = '├' + '─' * (indent - 1)

self.turn_horiz = '└' + '─' * (indent - 1)

self.traverses = {

'df': self.df,

'do': self.do,

'ff': self.ff,

'od': self.od

}

self.listdir = os.listdir if show_hidden else listdir_nohidden

self.show_size = show_size

self.show_absolute_path_of_rootdir = show_absolute_path_of_rootdir

self.chmod(mode)

self.generate(path)

现在,我们来实现generate函数,它生成参数path对应的目录树。

def generate(self, path):

"""metadata: [(path, isfile?, size) or None], maybe use to open filesize: file size, or number of files in a Directory, is a string"""

assert os.path.isdir(path)

self.metadata = []

self.lines = [path]

if not self.show_absolute_path_of_rootdir:

self.lines[0] = os.path.basename(path)

self.traverse(path, '', 0)

if self.lines[-1] == '':

self.lines.pop()

self.metadata.pop()

if self.show_size:

sep = self.indent_space

size_len = max(len(md[2]) for md in self.metadata if md)

for i, mdata in enumerate(self.metadata):

size = mdata[2] if mdata else ' '

size = '%*s' % (size_len, size)

if self.lines[i]:

self.lines[i] = size + sep + self.lines[i]

self.tree = '\n'.join(self.lines) + '\n'

接着,为了方便后面遍历目录时保存数据,我们来写三个辅助函数

def get_dirs_files(self, dirpath):

dirs, files = [], []

for leaf in self.listdir(dirpath):

path = os.path.join(dirpath, leaf)

if os.path.isfile(path):

files.append((leaf, path))

else:

dirs.append((leaf, path))

self.metadata.append((dirpath, False, str(len(dirs) + len(files))))

return dirs, files

def add_dirs(self, dirs, prefix, recursive, layer):

fprefix = prefix + self.down_space

dprefix = prefix + self.vert_horiz

for dirname, path in dirs[:-1]:

self.lines.append(dprefix + dirname + self.dtail)

recursive(path, fprefix, layer + 1)

fprefix = prefix + self.indent_space

dprefix = prefix + self.turn_horiz

dirname, path = dirs[-1]

self.lines.append(dprefix + dirname + self.dtail)

recursive(path, fprefix, layer + 1)

def add_files(self, files, fprefix):

for filename, path in files:

size = str_size(os.path.getsize(path))

self.lines.append(fprefix + filename)

self.metadata.append((path, True, size))

if self.sparse and files:

self.lines.append(fprefix.rstrip())

self.metadata.append(None)

再接着,实现4种不同的遍历模式的函数

def df(self, dirpath, prefix, layer):

dirs, files = self.get_dirs_files(dirpath)

if layer < self.layer:

if dirs:

self.add_dirs(dirs, prefix, self.df, layer)

self.add_files(files, prefix + self.indent_space)

def do(self, dirpath, prefix, layer):

dirs, files = self.get_dirs_files(dirpath)

if layer < self.layer and dirs:

self.add_dirs(dirs, prefix, self.do, layer)

def ff(self, dirpath, prefix, layer):

dirs, files = self.get_dirs_files(dirpath)

if layer < self.layer:

if dirs:

self.add_files(files, prefix + self.down_space)

self.add_dirs(dirs, prefix, self.ff, layer)

else:

self.add_files(files, prefix + self.indent_space)

def od(self, dirpath, prefix, layer):

def add_leaf(leaf):

path = os.path.join(dirpath, leaf)

if os.path.isfile(path):

size = str_size(os.path.getsize(path))

self.lines.append(dprefix + leaf)

self.metadata.append((path, True, size))

if os.path.isdir(path):

self.lines.append(dprefix + leaf + self.dtail)

self.od(path, fprefix, layer + 1)

leaves = list(self.listdir(dirpath))

self.metadata.append((dirpath, False, str(len(leaves))))

if layer < self.layer and leaves:

leaves.sort()

fprefix = prefix + self.down_space

dprefix = prefix + self.vert_horiz

for leaf in leaves[:-1]:

add_leaf(leaf)

fprefix = prefix + self.indent_space

dprefix = prefix + self.turn_horiz

add_leaf(leaves[-1])

至此,目录树函数tree终于成功编写了。让我们把上面的代码连接起来,保存为tree.py文件。新建一个叫做SublimeDirectoryTree的目录,把tree.py拖进去,再在该目录下新建一个叫做Side Bar.py或main.py的文件,在里面写入如下代码(这个代码是有固定的格式的喔)

import os

import sublime

import sublime_plugin

from .tree import Tree

class SidebarMakeTreeCommand(sublime_plugin.WindowCommand):

def get_tree_settings(self):

settings = sublime.load_settings(

'SublimeDirectoryTree.sublime-settings')

tree_settings = settings.get('args', { "dir_tail_character": "/" })

tree_settings['dtail'] = tree_settings.pop("dir_tail_character")

return tree_settings

def is_visible(self, paths):

return len(paths) == 1 and os.path.isdir(paths[0])

def run(self, paths):

tree_settings = self.get_tree_settings()

tree = Tree(paths[0], **tree_settings)

text = "mode:%s\n\n" % tree.mode

text += tree.tree

view = self.window.new_file()

view.assign_syntax("tree.sublime-syntax")

view.set_name("%s.tr" % os.path.basename(paths[0]))

view.settings().set("font_face", "Lucida Console")

view.settings().set("word_wrap", False)

view.run_command("append", {"characters": text})

view.set_scratch(True)

view.set_read_only(True)

class SidebarCopyTreeCommand(SidebarMakeTreeCommand):

def run(self, paths):

tree_settings = self.get_tree_settings()

tree = Tree(paths[0], **tree_settings)

sublime.set_clipboard(tree.tree)

这样,我们就成功开发了一个SublimeText3编辑器的插件。当然,为了让我们的插件使用起来更加方便,我们还需要为它添加一些菜单:

[

{"caption": "-", "id": "folder_menus"},

{

"caption": "Copy Directory Tree",

"command": "sidebar_copy_tree",

"args": {"paths": []}

},

{

"caption": "View Directory Tree",

"command": "sidebar_make_tree",

"args": {"paths": []}

},

]

在同目录下保存为Side Bar.sublime-menu。

???这不就是Python的字典吗?

不,你错了,它只是长得像Python的字典,实际上它是JSON数据文件格式。

喔对了,上面不是说我们的插件支持一些选项吗?给忘了,让我们来添加一个设置文件吧

{

/*

* mode explain:

* df: Directory First,

* do: Directory Only,

* ff: File First,

* od: Ordered

*/

"args": {

"mode": "ff",

"layer": 3,

"indent": 4,

"sparse": false,

"show_size": false,

"show_hidden": false,

"dir_tail_character": "/",

"show_absolute_path_of_rootdir": false

}

}

在同目录下保存为SublimeDirectoryTree.sublime-settings。

把SublimeDirectoryTree文件夹整个复制到SublimeText的插件目录下,我们就可以使用自己的插件了。

整个流程下来,你是不是发现开发一个能够实用的SublimeText3插件是如此的简单。

完整的插件位于absop/SublimeDirectoryTree​github.com

有兴趣的同学可以参考参考。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值