現(xiàn)在我們來(lái)簡(jiǎn)單的實(shí)現(xiàn)一個(gè) Node 命令行(cli)文件管理程序。
效果演示
file.gif
需求分析
- 程序在命令行中運(yùn)行,那么程序需要通過(guò)node命令來(lái)執(zhí)行,然后通過(guò)終端來(lái)實(shí)現(xiàn)用戶的交互。
- 在程序啟動(dòng)后需要獲取程序當(dāng)前運(yùn)行目錄下的文件列表。
- 用顏色來(lái)區(qū)分文件與文件夾。
- 在選擇某個(gè)文件時(shí),則打開該文件。
- 在選擇某個(gè)文件夾時(shí),則打開該文件夾。
- 在輸入錯(cuò)誤的指令時(shí),提醒用戶輸入錯(cuò)誤,重新輸入。
- 在輸入 back 指令時(shí),返回上一級(jí)。
- 在輸入 end 指令時(shí),退出程序。
項(xiàng)目解析
創(chuàng)建模塊
- 我們先創(chuàng)建一個(gè)項(xiàng)目目錄=> fileProject 。
- 新建 package.json 文件,用來(lái)對(duì)程序進(jìn)行依賴管理,本程序還用到了colors 模塊,可以安裝如下定義。然后 npm install 安裝依賴來(lái)測(cè)試該文件是否準(zhǔn)確定義。
//package.json
{
"name": "fileproject",
"version": "0.0.1",
"description": "this file project",
"dependencies": {
"colors": "^1.1.2"
}
}
程序?qū)崿F(xiàn)
- 新建一個(gè) index.js 文件。
- 流:process 全局對(duì)象包含了三個(gè)流對(duì)象:
-stdin:標(biāo)準(zhǔn)輸入
-stdout:標(biāo)準(zhǔn)輸出
-stderr:標(biāo)準(zhǔn)錯(cuò)誤 - fs模塊:
-readFile:讀取文件
-readdir:讀取目錄
-stat:讀取文件與目錄的信息
//index.js
//引入fs
var fs = require('fs');
//引入colors
require('colors');
//歡迎信息
console.log('歡迎使用管子文件管理系統(tǒng) V0.0.1'.rainbow);
//文件系統(tǒng)
function selFile(baseUrl) {
//異步讀取目錄狀態(tài)
fs.readdir(baseUrl, function(err, files) {
//錯(cuò)誤判斷
if (err) return;
//空文件夾判斷
if (!files.length) console.log('當(dāng)前文件夾沒(méi)有文件!\n'.red);
//輸出當(dāng)前路徑
var Urls = '\n當(dāng)前路徑' + baseUrl;
console.log(Urls.red);
//輸出當(dāng)前的文件夾及文件信息
function file(i) {
var fileName = files[i];
//獲取文件信息
fs.stat(baseUrl + '\\' + fileName, function(err, stat) {
if (err) return;
var filest = ++i + '. ' + fileName + '\n';
//判斷是否為文件夾
if (stat.isDirectory()) {
//文件夾
process.stdout.write(filest.yellow);
} else {
//文件
process.stdout.write(filest.blue);
}
// 判斷是否獲取完所有的文件信息
if (i == files.length) {
//執(zhí)行下一步方法
read();
} else {
//繼續(xù)獲取
file(i);
}
});
}
//執(zhí)行文件信息獲取方法
file(0);
//用戶輸入
function read() {
process.stdout.write('\n請(qǐng)輸入你要打開的文件或文件夾序號(hào)(輸入back返回上一層,end退出程序):'.red);
//輸入
process.stdin.resume();
//設(shè)置編碼
process.stdin.setEncoding('UTF-8');
//獲取用戶輸入
process.stdin.once('data', option);
}
//用戶輸入處理
function option(data) {
//停止用戶輸入
process.stdin.pause();
//判斷是否是back返回輸入
if (data.split('\r')[0] == 'back') {
//獲取上一級(jí)地址地址并打開文件夾
selFile(baseUrl.split('\\').slice(0, baseUrl.split('\\').length - 1).join('\\'));
} else if (data.split('\r')[0] == 'end') {
//關(guān)閉當(dāng)前程序
console.log('程序已退出...'.yellow);
process.exit();
} else {
//判斷序號(hào)對(duì)應(yīng)的文件是否存在
if (!files[Number(data) - 1]) {
process.stdout.write('您的輸入有誤!請(qǐng)重新輸入!'.red);
read();
} else {
fs.stat(baseUrl + '\\' + files[Number(data) - 1], function(err, stat) {
if (err) return;
//檢查選中的是否為文件夾
if (stat.isDirectory()) {
// 打開文件夾
selFile(baseUrl + '\\' + files[Number(data) - 1]);
} else {
// 輸出文件內(nèi)容
fs.readFile(baseUrl + '\\' + files[Number(data) - 1], 'UTF-8', function(err, conent) {
//文件路徑
var filePath = baseUrl + '\\' + files[Number(data) - 1];
//輸出文件名
console.log(filePath.split('\\')[filePath.split('\\').length - 1].yellow);
// 輸出內(nèi)容
console.log(conent.blue);
// 重新打開當(dāng)前文件夾
selFile(baseUrl);
})
}
});
}
}
}
});
}
//打開默認(rèn)程序啟動(dòng)地址
selFile(process.cwd());