一个命令行工具实例
这个实例包含了处理进程中的stdin
和stdout
相关的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);
});