
這兩天在工作之余學(xué)習(xí)
Node.js,整理了其中一些基礎(chǔ)api,并寫了一些基礎(chǔ)的demo下面是自己對(duì)于
path、buffer、event、fs這幾個(gè)常用到api的一些用法整理。
一,PATH
模塊提供了一些工具函數(shù),用于處理文件與目錄的路徑。
1,path.normalize(path)
path.normalize() 方法會(huì)規(guī)范化給定的 path,并解析 '..' 和 '.' 片段
例子
const { normalize } = require('path');
console.log(normalize('/user//local/bin'));
console.log(normalize('/user//local/../bin'));
結(jié)果如圖

2,path.join([...paths])
path.join() 方法使用平臺(tái)特定的分隔符把全部給定的 path 片段連接到一起,并規(guī)范化生成的路徑。
例子
const { normalize,join } = require('path');
console.log(join('/foo', 'bar', 'baz/asdf', 'quux', '..'));
console.log(join('/usr','../local','bin/'));
結(jié)果如圖

3,path.resolve([...paths])
path.resolve() 方法會(huì)把一個(gè)路徑或路徑片段的序列解析為一個(gè)絕對(duì)路徑。
例子
const { resolve } = require('path');
console.log(resolve('./'));
console.log(resolve('/foo/bar', './baz'));
console.log(resolve('/foo/bar', '/tmp/file/'));
結(jié)果如圖

4,basename:文件名;extname:文件的拓展名;dirnam:目錄名文件所在的路徑
例子
const { dirname,extname,basename } = require('path');
const filePath = '/usr/local/bin/no.txt';
console.log(dirname(filePath)); // '/usr/local/bin'
console.log(extname(filePath)); // '.txt'
console.log(basename(filePath)); // 'no.txt'
結(jié)果如圖

5,path.parse,path.format
path.parse() 方法返回一個(gè)對(duì)象,對(duì)象的屬性表示 path 的元素。返回的對(duì)象有以下屬性:root、dir、base、ext、name;
path.format() 方法會(huì)從一個(gè)對(duì)象返回一個(gè)路徑字符串。 與 path.parse() 相反。
例子
const { parse,format } = require('path');
const filePath = '/usr/local/bin/node_module/package.json';
const ret = parse(filePath);
console.log(ret)
console.log(format(ret));
結(jié)果如圖

需要注意的點(diǎn)
當(dāng) pathObject 提供的屬性有組合時(shí),有些屬性的優(yōu)先級(jí)比其他的高:
- 如果提供了
pathObject.dir,則pathObject.root會(huì)被忽略 - 如果提供了
pathObject.base存在,則pathObject.ext和pathObject.name會(huì)被忽略
//1, 如果提供了 `dir`、`root` 和 `base`,則返回 `${dir}${path.sep}${base}`。
// `root` 會(huì)被忽略。
path.format({
root: '/ignored',
dir: '/home/user/dir',
base: 'file.txt'
});
// 返回: '/home/user/dir/file.txt'
// 2,如果沒有指定 `dir`,則 `root` 會(huì)被使用。
// 如果只提供了 `root` 或 `dir` 等于 `root`,則平臺(tái)的分隔符不會(huì)被包含。
// `ext` 會(huì)被忽略。
path.format({
root: '/',
base: 'file.txt',
ext: 'ignored'
});
// 返回: '/file.txt'
// 3,如果沒有指定 `base`,則 `name` + `ext` 會(huì)被使用。
path.format({
root: '/',
name: 'file',
ext: '.txt'
});
// 返回: '/file.txt'
6,sep,delimiter,win32,posix
delimiter提供平臺(tái)特定的路徑分隔符:
- Windows 上是
; - POSIX 上是
:
sep提供了平臺(tái)特定的路徑片段分隔符:
- Windows 上是
\ - POSIX 上是
/
path.win32 屬性提供了 path 方法針對(duì) Windows 的實(shí)現(xiàn);
path.posix 屬性提供了 path 方法針對(duì) POSIX 的實(shí)現(xiàn)。
例子
// mac下
const { sep,delimiter,win32,posix } = require('path');
console.log('PATH:',process.env.PATH); // "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
console.log('sep:',sep); // "/"
console.log('win sep:',win.sep); // "\"
console.log('delimiter:',delimiter); // ":"
console.log('delimiter:',win.delimiter); // ";"
結(jié)果如圖

7,關(guān)于路徑的注意點(diǎn)
__dirname,process.cwd(),path.resolve()三者的區(qū)別
例子
//1,在項(xiàng)目的根目錄執(zhí)行:
$ ~/Desktop/node_demo $ node index.js
============代碼============
const path = require('path');
const mod = require('./test.js');
console.log(mod.testVar); // 5
console.log('__dirname',__dirname); // "/Users/fujiawei/Desktop/node_demo"
console.log('process.cwd()',process.cwd()); // "/Users/fujiawei/Desktop/node_demo"
console.log('./',path.resolve('./')); // "/Users/fujiawei/Desktop/node_demo"
===================
//2,在Desktop執(zhí)行
$ ~/Desktop $ node node_demo/index.js
============代碼============
const path = require('path');
const mod = require('./test.js');
console.log(mod.testVar); // 5
console.log('__dirname',__dirname); // "/Users/fujiawei/Desktop/node_demo"
console.log('process.cwd()',process.cwd()); // "/Users/fujiawei/Desktop"
console.log('./',path.resolve('./')); // "/Users/fujiawei/Desktop"
-
__dirname與__filename總是返回文件的絕對(duì)路徑,即物理磁盤上的路徑 -
process.cwd()總是返回執(zhí)行node命令時(shí)所在的文件夾路徑,當(dāng)前在哪里啟動(dòng)的腳本路徑 -
./在require方法中總是相對(duì)當(dāng)前文件所在文件夾的路徑;在其他的地方和process.cwd()一樣,相對(duì)node啟動(dòng)文件夾
二,buffer
Buffer處理二進(jìn)制數(shù)據(jù)流;實(shí)例類似整數(shù)數(shù)組;大小固定;C++代碼在V8堆外分配物理內(nèi)存
1,Buffer.alloc()
-
size新建的Buffer期望的長度 -
fill用來預(yù)填充新建的Buffer的值。 默認(rèn):0 -
encoding如果fill是字符串,則該值是它的字符編碼。 默認(rèn):'utf8'
分配一個(gè)大小為 size 字節(jié)的新建的 Buffer 。 如果 fill 為 undefined ,則該 Buffer 會(huì)用 0 填充。
例子
var buf1 = Buffer.alloc(10);
console.log(buf1);
結(jié)果如圖

例子
var buf1 = Buffer.alloc(10,1);
console.log(buf1);
結(jié)果如圖

2,Buffer.allocUnsafe()
分配一個(gè)大小為 size 字節(jié)的新建的 Buffer 。 如果 size 大于 buffer.constants.MAX_LENGTH 或小于 0,則拋出 RangeError錯(cuò)誤。 如果 size 為 0,則創(chuàng)建一個(gè)長度為 0 的 Buffer。
以這種方式創(chuàng)建的 Buffer 實(shí)例的底層內(nèi)存是未初始化的。 新創(chuàng)建的 Buffer 的內(nèi)容是未知的,且可能包含敏感數(shù)據(jù)。 可以使用 buf.fill(0)初始化 Buffer實(shí)例為0。
例子
var buf1 = Buffer.allocUnsafe(10);
console.log(buf1);
結(jié)果如圖

3,Buffer.from()
array
通過一個(gè)八位字節(jié)的 array 創(chuàng)建一個(gè)新的 Buffer 。
例子
var buf1 = Buffer.from([1,2,3]);
console.log(buf1);
結(jié)果如圖

例子
var buf1 = Buffer.from('text'); // 默認(rèn)utf8
console.log(buf1);

結(jié)果如圖
var buf1 = Buffer.from('text', 'base64')
console.log(buf1);

4,Buffer.byteLength()
-
string要計(jì)算長度的值 -
encoding如果string是字符串,則這是它的字符編碼。 默認(rèn):'utf8' - 返回:
string包含的字節(jié)數(shù)
返回一個(gè)字符串的實(shí)際字節(jié)長度。 這與 String.prototype.length 不同,因?yàn)槟欠祷刈址?strong>字符數(shù)。
例子
var buf1 = Buffer.byteLength('text')
console.log(buf1); // 4
var buf2 = Buffer.byteLength('測(cè)試')
console.log(buf2); // 6
5,Buffer.isBuffer()
如果 obj 是一個(gè) Buffer 則返回 true ,否則返回 false 。
var buf1 = Buffer.isBuffer({})
console.log(buf1); // false
var buf2 = Buffer.isBuffer(Buffer.from([1,2,3]))
console.log(buf2); // true
6,Buffer.concat()
-
list要合并的Buffer或Uint8Array實(shí)例的數(shù)組 -
totalLength合并時(shí)list中Buffer實(shí)例的總長度 - 返回:
buffer
返回一個(gè)合并了 list 中所有 Buffer 實(shí)例的新建的 Buffer 。
例子
const buf1 = Buffer.from('this ');
const buf2 = Buffer.from('is ');
const buf3 = Buffer.from('good!');
var buf = Buffer.concat([buf1,buf2,buf3])
console.log(buf.toString());
結(jié)果如圖

接下來是buffer的實(shí)例方法:
7,buf.length
返回 buf 在字節(jié)數(shù)上分配的內(nèi)存量。 注意,這并不一定反映 buf 內(nèi)可用的數(shù)據(jù)量。
例子
var buf = Buffer.from('good!')
console.log(buf.length); // 5
8,buf.toString()
將buffer轉(zhuǎn)化為字符串
例子
var buf = Buffer.from('good!')
console.log(buf.toString()); // good!
console.log(buf.toString('base64')); // Z29vZCE=
9,buf.fill()
填充buffer。
-
value用來填充buf的值。 -
offset開始填充buf前要跳過的字節(jié)數(shù)。默認(rèn):0。 -
end結(jié)束填充buf的位置(不包含)。默認(rèn):buf.length。 -
encoding如果value是一個(gè)字符串,則這是它的字符編碼。默認(rèn):'utf8'。 - 返回:
buf的引用。
如果未指定 offset 和 end,則填充整個(gè) buf。 這個(gè)簡化使得一個(gè) Buffer 的創(chuàng)建與填充可以在一行內(nèi)完成。
例子
var buf1 = Buffer.allocUnsafe(10);
console.log(buf1)
console.log(buf1.fill(10,2,6)); // good!
結(jié)果如圖

10,buf.equals()
如果 buf 與 otherBuffer 具有完全相同的字節(jié),則返回 true,否則返回 false。
例子
var buf4 = Buffer.from('test');
var buf5 = Buffer.from('test');
var buf6 = Buffer.from('test!');
console.log(buf4.equals(buf5)); // true
console.log(buf4.equals(buf6)); // false
11,buf.indexOf()
如javascript的indexOf的方法。
例子
var buf4 = Buffer.from('test');
console.log(buf4.indexOf('es')); // 1
console.log(buf4.indexOf('a')); // -1
12,buffer 打印例子
一個(gè)文字的字符是3,所以會(huì)出現(xiàn)亂碼。
例子
const buf = Buffer.from('中文字符串!');
for (let i = 0;i < buf.length; i += 5) {
const b = Buffer.allocUnsafe(5);
buf.copy(b, 0, i);
console.log(b.toString());
}
const StringDecoder = require('string_decoder').StringDecoder;
const decoder = new StringDecoder('utf8');
for (let i = 0;i < buf.length; i += 5) {
const b = Buffer.allocUnsafe(5);
buf.copy(b, 0, i);
console.log(decoder.write(b));
}
結(jié)果如圖

三,event,事件機(jī)制
事件驅(qū)動(dòng)和異步i/o,大多數(shù) Node.js 核心 API 都采用慣用的異步事件驅(qū)動(dòng)架構(gòu),其中某些類型的對(duì)象(觸發(fā)器)會(huì)周期性地觸發(fā)命名事件來調(diào)用函數(shù)對(duì)象(監(jiān)聽器)。
所有能觸發(fā)事件的對(duì)象都是 EventEmitter 類的實(shí)例。 這些對(duì)象開放了一個(gè) eventEmitter.on() 函數(shù),允許將一個(gè)或多個(gè)函數(shù)綁定到會(huì)被對(duì)象觸發(fā)的命名事件上。 事件名稱通常是駝峰式的字符串,但也可以使用任何有效的 JavaScript 屬性名。
當(dāng) EventEmitter 對(duì)象觸發(fā)一個(gè)事件時(shí),所有綁定在該事件上的函數(shù)都被同步地調(diào)用。 監(jiān)聽器的返回值會(huì)被丟棄。
1,最簡單的demo
例子
const EventEmitter = require('events');
class CustomEvent extends EventEmitter {}
const ce = new CustomEvent();
ce.on('test', ()=> {
console.log('this is test');
})
setInterval(()=>{
ce.emit('test');
},500);
結(jié)果如圖

2,定制拋出錯(cuò)誤的事件處理程序
例子
const EventEmitter = require('events');
class CustomEvent extends EventEmitter {}
const ce = new CustomEvent();
ce.on('error', (err,time) => {
console.log(err);
console.log(time);
})
ce.emit('error',new Error('失敗了'), Date.now()); // 第二個(gè)是穿給時(shí)間的參數(shù)
結(jié)果如圖

3,只響應(yīng)一次事件
例子
const EventEmitter = require('events');
class CustomEvent extends EventEmitter {}
const ce = new CustomEvent();
ce.once('test', () => {
console.log('test event');
})
setInterval(()=>{
ce.emit('test');
},500);
結(jié)果如圖

4,刪除事件
分為刪除事件的具體的某一個(gè)方法:ce.removeListener(事件名,具體方法)
例子
const EventEmitter = require('events');
class CustomEvent extends EventEmitter {}
const ce = new CustomEvent();
function fn1 () {
console.log('fn1');
}
function fn2 () {
console.log('fn2');
}
ce.on('test',fn1);
ce.on('test',fn2);
setInterval(()=>{
ce.emit('test');
},500);
setInterval(()=>{
// 移除某一個(gè)方法
ce.removeListener('test',fn1); // 刪除test事件的fn1函數(shù)
},1500);
結(jié)果如圖

刪除事件所有方法,即刪除事件:ce.removeAllListeners(事件名)
例子
const EventEmitter = require('events');
class CustomEvent extends EventEmitter {}
const ce = new CustomEvent();
function fn1 () {
console.log('fn1');
}
function fn2 () {
console.log('fn2');
}
ce.on('test',fn1);
ce.on('test',fn2);
setInterval(()=>{
ce.emit('test');
},500);
setInterval(()=>{
// 移除所有的事件
ce.removeAllListeners('test');
},1500);
結(jié)果如圖

四,fs:文件系統(tǒng)
文件 I/O 是對(duì)標(biāo)準(zhǔn) POSIX 函數(shù)的簡單封裝。 通過 require('fs') 使用該模塊。 所有的方法都有異步和同步的形式。
異步方法的最后一個(gè)參數(shù)都是一個(gè)回調(diào)函數(shù)。 傳給回調(diào)函數(shù)的參數(shù)取決于具體方法,但回調(diào)函數(shù)的第一個(gè)參數(shù)都會(huì)保留給異常。 如果操作成功完成,則第一個(gè)參數(shù)會(huì)是 null 或 undefined。
1,fs.readFile:讀文件
例子
fs.readFile('./index.js',(err,data) => {
if(err) throw err;
console.log(data);
});
結(jié)果如圖

buffer變成string
fs.readFile('./index.js','utf8', (err,data) => {
if(err) throw err;
console.log(data);
});
結(jié)果如圖

報(bào)錯(cuò):找不到相應(yīng)的文件夾的時(shí)候
例子
fs.readFile('./index.jss','utf8', (err,data) => {
if(err) throw err;
console.log(data);
});
結(jié)果如圖

同步讀文件
const data = fs.readFileSync('./test.js','utf8');
console.log(data);
結(jié)果如圖

2,寫文件:fs.writeFile
例子
fs.writeFile('./test1.js','this is test','utf8',(err) => {
if(err) throw err;
console.log('done');
});
結(jié)果如圖

將buffer寫入到文件中去
const content = Buffer.from('this is test');
fs.writeFile('./test1.js', content, (err) => {
if(err) throw err;
console.log('done');
});
結(jié)果如圖

3,文件信息:fs.stat
返回的stats有判斷是否為文件和是否為文件夾的方法;
fs.stat('./index.js',(err, stats) => {
if(err) throw err;
console.log("是否為文件:",stats.isFile()); // 是否為文件
console.log("是否為文件夾:",stats.isDirectory()); // 是否為文件夾
console.log("stats詳細(xì)信息:",stats);
});
結(jié)果如圖

查找文件是否存在
fs.stat('./index.jsf',(err, stats) => {
if(err) {
console.log('文件不存在');
return;
};
console.log(stats.isFile()); // 是否為文件
console.log(stats.isDirectory()); // 是否為文件夾
console.log(stats);
});
結(jié)果如圖

4,重命名:fs.rename:參數(shù)是要改名字的文件,需要修改成的名字,以及回調(diào)函數(shù)。
例子
fs.rename('./test1.js','test.txt', (err) => {
if(err) {
if(err) throw err;
};
console.log('done');
});
5,刪除fs.unlink
例子
fs.unlink('./test.txt', (err) => {
if(err) throw err;
console.log('done');
});
6,查找文件夾fs.readdir
fs.readdir('./', (err,files) => {
if(err) throw err;
console.log(files);
});
結(jié)果如圖

7,創(chuàng)建文件夾fs.mkdir
fs.mkdir('aaaa', (err) => {
if(err) throw err;
});
8,刪除文件夾fs.rmdir
fs.rmdir('aaaa', (err) => {
if(err) throw err;
});
9,監(jiān)視文件的變化fs.watch,會(huì)監(jiān)視每一次文件的變化,以及變化的文件名。
fs.watch('./', {
recursive:true //是否遞歸
}, (eventType, filename) => { // 變化類型與變化文件名
console.log(eventType, filename);
});
結(jié)果如圖

10,比較復(fù)雜的,stream是流的意思,方向與數(shù)據(jù)是條件,用到的場(chǎng)景看電影等
fs.createReadStream讀流,pipe控制流的方向,fs.createWriteStream是創(chuàng)建一個(gè)流,并可以向里面寫數(shù)據(jù),這里模擬異步的方式,當(dāng)隨機(jī)數(shù)小于7的時(shí)候我們就往text.txt中寫數(shù)據(jù)。
例子
// 創(chuàng)建一個(gè)stream。
const rs = fs.createReadStream('./test.js');
rs.pipe(process.stdout);// 控制方向
// 開始寫stream,創(chuàng)建一個(gè)stream。
const ws = fs.createWriteStream('./text.txt');
const tid = setInterval(() => {
const num = parseInt(Math.random() * 10 );
console.log(num);
if(num < 7) {
ws.write(num + '');
} else {
clearInterval(tid);
ws.end();
}
}, 200);
ws.on('finish',() => {
console.log('done');
})
結(jié)果如圖

寫入到text.txt的值

11,解決回調(diào)地獄,我們使用promise與async await解決
例子
const promiseify = require('util').promisify;
var read = promiseify(fs.readFile);
read('./fs.js').then(data => {
console.log(data.toString());
}).catch(ex => {
console.log(ex)
})
結(jié)果如圖

async await: async function在 node > 8.0 就可以使用。
const promiseify = require('util').promisify;
var read = promiseify(fs.readFile);
//
async function test() {
try{
const content = await read('./fs.js');
console.log(content.toString());
} catch (ex) {
console.log(ex)
}
}
test()
結(jié)果如圖

五,參考文件
此篇文章是參考了Node.js中文網(wǎng),自己寫的一些api小demo
希望這篇文章對(duì)大家能有幫助,來自一個(gè)奔跑在前端路上的前端小白。