htree,一款模仿 tree 命令的本地文件结构查看工具

htree 介绍

首先,介绍一下 htree 这一款工具。htree 是一款用于在 node 环境下运行的工具,安装之后可以直接在 node 命令行窗口输入 htree 进行使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
E:\Git\xovel\htree
├─index.js
├─LICENSE
├─package.json
├─README.md
├─bin
│ └─htree
├─docs
│ └─help
├─node_modules
└─util
├─genText.js
├─getByteLength.js
├─getSize.js
├─getTextList.js
└─walk.js

以上代码为在 htree 开发文件夹的命令行工具下执行命令 htree 生成的结果。

参数简介

htree 目前版本为 0.2.0,支持的参数如下:

ignore

忽略列表,为一个数组,包括文件和文件夹。在列表之中的值均会跳过不进行处理。

exclude

排除的文件夹。该值如果设置,应该是一个正则表达式。符合正则表达式匹配的文件夹会跳过。

maxDepth

读取文件夹的最大深度。该深度是基于当前传入的文件夹。

gap

布尔值,为真则在文件/文件夹名称前面添加一个空格。

concatLength

节点前缀和文件/文件名之间的连接符的长度。

indent

布尔值,为真则在子文件/文件夹前面添加空格作为缩进。

indentLength

上面的缩进的空格的长度。

suffix

布尔值,是否在文件夹后面添加一个后缀,默认不添加。

strSuffix

上面的后缀的文本,默认为 /

strComment

注释标识符,类型为字符串。如果设置为非空字符串,htree 会自动计算文件/文件夹最大长度,然后再拼接 padLength 长度的空格,之后拼接 strComment 作为列表文本。非最大长度的行会使用空格进行补正对齐。

padLength

补齐 strComment 所用的空格的长度。

dir

htree 的执行主目录,默认为当前命令行窗口所在的文件夹。

folder

布尔值,为真时只读取文件夹,跳过非文件夹的部分(即普通文件)。

sort

布尔值,为真时对同级的文件/文件夹列表进行排序。通常这个设置没有什么效果,但在处理一些特殊字符开头的文件/文件夹之时会用到。默认为真。

如下划线 _ 开头的文件/文件夹默认排在后面。

size

布尔值,为真时显示文件的大小,如果 strComment未指定,则将其设置为 #

order

对同级文件/文件夹进行归类显示的参数。为字符串 after 时,文件会被统一放在文件夹后面;为真的其他情况时,文件会统一放在文件夹前面;为假则不做任何处理。

showDir

布尔值,为真时在最开始处显示当前执行的文件夹路径。

dot

布尔值,为真时处理以点号 . 号开头的文件夹,否则跳过。

underline

布尔值,为真时处理以下划线 _ 开头的文件夹,否则跳过。

命令行参数

上面的所有设置均可以通过命令行方式进行参数指定,指定方式为小写连字符风格的字符串加上 -- 的前缀。如要指定最大文件夹访问深度 maxDepth10,则使用命令:htree --max-depth 10,或者 htree --max-depth=10

支持的短命令列表如下:

  • -v,即 --version,显示当前 htree 的版本号。
  • -h,即 --help,显示当前 htree 的帮助文件。
  • -f,即 --folder
  • -d,即 --dir
  • -i,即 --ignore
  • -o,即 --output
  • -s,即 --show-dir
  • -m,即 --max-depth

为布尔值的参数,可以通过前缀 --no- 设置为 false 值。

在设置 --dir--output--exclude--str-comment 的值之时,必要时请对特殊字符进行转义操作。

缘起

为什么要开发这一款工具呢?其实很早以前就有过这样的想法,但是后来由于工作忙碌就搁置了。直到最近在处理一个树形结构的展示的时候,需要通过设置自定义数据来实现多级树结构的嵌套生成。这个方式与之前设想的文件夹结构展开方式类似,于是决定将这个项目正式开发出来。

经过陆陆续续的改动,对参数配置进行了较大幅度的修改,版本号目前 0.2.0。项目已经趋于稳定,想来应该是没有什么太大的改动了。

模块化

这个项目里面,算是体验了一把模块化编程。大部分功能都抽离成了模块,虽然也没多少个

递归

在获取多级文件夹时候用到了以前上学时期学过的一个技术:递归。

原则上,没有无限极的目录深度,所以递归调用肯定会有某个结束的场景。但是我还是设定了默认的最大目录深度为 5

npm 相关

在进行本地开发的时候,我并没有创建 node_modules 文件夹,实际开发中,也没有依赖其他的项目,而在本地连接发布 npm link 的时候会自动进行创建。这也是为什么上面的目录中会有这个文件夹而上传到 github 上面的时候由于默认机制的原因忽略了。之前进行 npm 发布的遇到过一个不大不小的问题,这一次的发布又遇到了,是的,我又设置了淘宝的国内镜像源。

遇到的问题

开发过程难免碰到一些乍看起来不可思议的问题,比如在获取 windows 磁盘根目录下的文件列表时,由于部分系统文件夹默认禁止访问,如 System Volume Information。即便是开启了管理员权限,也不能直接访问这些文件/文件夹。经过一番思考,目前采用了 try/catch 命令来避免程序报错,并退出当前操作。一些经过特意设置的文件夹如加密过的,也是不能直接读取其属性的,这就无法判断是否是文件夹了。

当然,根据提供的 ignoreexclude 参数,可以跳过这些文件/文件夹的访问。

另一个问题是命令行执行的时候,获取当前文件夹错误,原因是最开始的命令行文件 bin/htree 没有对执行的环境进行指定,亦即在最开始的部分并没有这样一句代码:#!/usr/bin/env node。这段代码的作用的是让程序在运行时候的运行环境变为 node,设置为这样之后在获取目录的时候调用 process.cwd() 等方法就表现正常了。

在处理字符串长度的时候,获取字符串的实际占用长度的时候存在一个不大不小的问题,部分字符会占据两个字母的长度,比如中文。由于本人当前主要是在中文环境下面工作,故此在获取字符串长度的时候直接将中文汉字和标点转成了两个字母长度的,再返回其长度,这样来保证设置了 size 或者 strComment 参数的时候,右侧的标识符能够对齐显示。

文件字节长度的计算,这里是采用下面这段代码来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function getSize(size) {
let suffix = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB', 'DB', 'NB'];
let i = 0;

while (size >= 1000) {
size /= 1024;
i++;
}

if (i >= suffix.length) {
return '...';
}

return (i === 0 ? size : size.toFixed(2)) + ' ' + suffix[i];
}

为此还特意去查阅了一下计算机中的相关单位,还是挺有意思的。

关于代码规范

htree 其实并没有遵循特定的编码规范,当前的编码风格是自己设定的一套风格,即 zob,同样的由于各种原因,该项目并没有进行公布。参考了部分谷歌的JS 编码风格以及一些当前项目常用的 ESLint 规则。

参考项目

所谓前人栽树,后人乘凉,在完成 htree 这个项目的过程中,遍寻了大量的资料。

命令行代码主要是仿照 marked 项目下的 bin/marked 来编写的。该项目也是已经长久搁置的 zmd 项目的核心参考资源。原本在实现命令行参数的读取的时候要采用某些依赖,比如 yargscommander.js,但后来心想,干脆就自己尝试编写纯粹的命令行读取方法吧,就写成了现在这个样子的了。

nodejs.org 的官网上的 API 文档也提供了不少解决方案,主要是文件读取与写入方面的。


htree 项目的名字来源,看起来是 h + tree 的组合,粗看之下不会有人知道 h 代表了什么,但是我想要说的是其实这个是一个名字的谐音。嗯,是的,文本到底就结束了,希望后续能做制作一些方便使用的工具,这样也比较符合清风工具的总纲:简易、实用。