了不起的NodeJS命令行工具

一个命令行工具实例

这个实例包含了处理进程中的stdinstdout相关的api,以及文件系统有关的api,使用回调和事件机制来实现并发,主要锻炼基于非阻塞事件的I/O编程中的流控制。

// 声明模块依赖
const fs = require('fs');
// 这里使用我发布的的一个工具函数做打印工具
const print = require('idiv-utils').print;

// 存储stat, 避免handleUserInput再次fs.stat
const stats = [];
const EXIT = 'exit';
const GREETING = '\nEnter your choose index or \'exit\' ';

const printGreeting = function(GREETING, color) {
    var colorNum = Number(color);
    process.stdout.write('\033' + `[${ isNaN(colorNum) ? 90 : colorNum }m` + GREETING + '\033[39m');
};

// 遍历完根目录后执行的函数
const readFile = function readFile(files) {
    process.stdin.setEncoding('utf8');
    process.stdin.resume();
    printGreeting(GREETING);

    process.stdin.on('data', function(data) {
        handleUserInput(data, files);
    });
};

const handleFile = function file(i, files) {
    var fileName = files[i];
    fs.stat(process.cwd() + '/' + fileName, function(err, stat) {
        // 暂不处理错误 return 掉
        if (err) return;
        stats[i] = stat;
        // 调用stat.isDirectory判断是否为目录
        const printArgs = stat.isDirectory() ? [fileName + '--是目录', 96] : [fileName + '--是文件', 93];
        print(...printArgs);

        if (++i === files.length) {
            return readFile(files);
        } else {
            // 递归调用file直至遍历完所有子文件和目录
            return file(i, files);
        }
    });
};

// 用户输入选择后会触发process.stdin的data事件, 这是该事件的间接回调
const handleUserInput = function handleUserInput(data, files) {
    if (data.toString().trim() === EXIT) {
        // 后面没有io事件时, node会自动退出
        process.stdin.pause();
        process.stdin.removeAllListeners();
        return print('Good bye, welcomne next use!');
    }

    var fileName = files[Number(data)];
    if (!fileName) {
        printGreeting(data.toString().trim() + '不存在', 91);
        printGreeting(GREETING);
    } else {
        // 定位用户所选文件的绝对路径
        const path = __dirname + '/' + fileName;
        if (stats[Number(data)].isDirectory()) {
            fs.readdir(path, function(err, data) {
                if (err) return;
                print(fileName + '目录下有: ' + data.length + '文件');
                data.forEach(function(file) {
                    print('-- ' + file);
                });
                printGreeting(GREETING);
            });
        } else {
            fs.readFile(path, function(err, data) {
                print(data.toString().replace(/\s+/g, ''), 90);
                printGreeting(GREETING);
            });
        }
    }
};

// 读取根目录
fs.readdir(process.cwd(), function(err, files) {
    // 暂不处理错误
    if (err) return;

    handleFile(0, files);
});
posted @ 2018-02-09 21:49  xvivx  阅读(194)  评论(0编辑  收藏  举报