本文的主要內(nèi)容是對(duì)nodejs提供的一些重要模塊蜕琴,結(jié)合官方API進(jìn)行介紹莱预,遇到精彩的文章抛寝,我會(huì)附在文中并標(biāo)明了出處氧枣。主要包括如下7個(gè)模塊
- path 模塊
- http 模塊
- fs 模塊
- url 模塊
- query string 模塊
- os 模塊
- stream 模塊
轉(zhuǎn)載請(qǐng)注明出處沐兵,多謝支持~
path 路徑相關(guān)模塊
模塊簡(jiǎn)介
nodejs path 模塊提供了一些用于處理文件路徑的工具函數(shù),我們可以通過(guò)如下方式引用它
var path = require("path")
path.normalize(p)
標(biāo)準(zhǔn)化路徑字符串便监,處理冗余的“..”扎谎、“.”、“/”字符:
原則:
對(duì)window系統(tǒng)烧董,目錄分隔為'',對(duì)于UNIX系統(tǒng)毁靶,分隔符為'/',針對(duì)'..'返回上一級(jí)逊移;/與\都被統(tǒng)一轉(zhuǎn)換path.normalize(p);
如果路徑為空预吆,返回.,相當(dāng)于當(dāng)前的工作路徑胳泉。
將對(duì)路徑中重復(fù)的路徑分隔符(比如linux下的/)合并為一個(gè)拐叉。
對(duì)路徑中的.、..進(jìn)行處理扇商。(類似于shell里的cd ..)
-
如果路徑最后有/凤瘦,那么保留該/。
var url1 = path.normalize('a/b/c/../user/vajoy/bin');
var url2 = path.normalize('a/b/c///../user/vajoy/bin/');
var url3 = path.normalize('a/b/c/../../user/vajoy/bin');
var url4 = path.normalize('a/b/c/.././///../user/vajoy/bin/..');
var url5 = path.normalize('a/b/c/../../user/vajoy/bin/../../');
var url6 = path.normalize('a/../../user/vajoy/bin/../../');
var url7 = path.normalize('a/../../user/vajoy/bin/../../../../');
var url8 = path.normalize('./a/.././user/vajoy/bin/./');console.log('url1:',url1); // a\b\user\vajoy\bin
console.log('url2:',url2); // a\b\user\vajoy\bin
console.log('url3:',url3); // a\user\vajoy\bin
console.log('url4:',url4); // a\user\vajoy
console.log('url5:',url5); // a\user
console.log('url6:',url6); // ..\user
console.log('url7:',url7); // ....
console.log('url8:',url8); // user\vajoy\bin\
path.join([path1], [path2], [...])
將多個(gè)路徑結(jié)合在一起钳吟,并轉(zhuǎn)換為標(biāo)準(zhǔn)化的路徑
var url1 = path.join('////./a', 'b////c', 'user/', 'vajoy', '..');
var url2 = path.join('a', '../../', 'user/', 'vajoy', '..');
var url3 = path.join('a', '../../', {}, 'vajoy', '..');
var url4 = path.join('path1', 'path2//pp\\', ../path3');
console.log('url1:',url1); // \a\b\c\user
console.log('url2:',url2); // ..\user
console.log('url3:',url3); // 存在非路徑字符串廷粒,故拋出異常
console.log('url4:',url4); // path1\path2\path3
path.resolve([from ...], to)
從源地址 from 到目的地址 to 的絕對(duì)路徑
原則
以應(yīng)用程序根目錄為起點(diǎn),根據(jù)參數(shù)字符串解析出一個(gè)絕對(duì)路徑
要注意的是,如果某個(gè) from 或 to 參數(shù)是絕對(duì)路徑(比如 'E:/abc'坝茎,或是以“/”開頭的路徑)涤姊,則將忽略之前的 from 參數(shù)。
// 下文中app的根目錄為D:\temp\test
var url1 = path.resolve('.', 'testFiles/..', 'trdLayer');
var url2 = path.resolve('..', 'testFiles', 'a.txt');
var url3 = path.resolve('D:/vajoy', 'abc', 'D:/a');
var url4 = path.resolve('abc', 'vajoy', 'ok.gif');
var url5 = path.resolve('abc', '/vajoy', '..', 'a/../subfile'); //'abc'參數(shù)將被忽略嗤放,源路徑改從'D:/vajoy'開始
console.log('url1:',url1); //D:\temp\test\trdLayer
console.log('url2:',url2); //D:\temp\testFiles\a.txt
console.log('url3:',url3); //D:\a
console.log('url4:',url4); //D:\temp\test\abc\vajoy\ok.gif
console.log('url5:',url5); //D:\subfile
path.relative(from, to)
獲取從 from 到 to 的相對(duì)路徑(即思喊,基于from路徑的兩路徑間的相互關(guān)系),可以看作 path.resolve 的相反實(shí)現(xiàn)
var url1 = path.relative('C:\\vajoy\\test\\aaa', 'C:\\vajoy\\impl\\bbb');
var url2 = path.relative('C:/vajoy/test/aaa', 'C:/vajoy/bbb');
var url3 = path.relative('C:/vajoy/test/aaa', 'D:/vajoy/bbb');
console.log('url1:',url1); //..\..\impl\bbb
console.log('url2:',url2); //..\..\bbb
console.log('url3:',url3); //D:\vajoy\bbb
- 如果from次酌、to指向同個(gè)路徑恨课,那么,返回空字符串岳服。
- 如果from剂公、to中任一者為空,那么吊宋,返回當(dāng)前工作路徑纲辽。
path.isAbsolute(path)
判斷 path 是否絕對(duì)路徑。這塊可以理解為璃搜,path 是否真的是一個(gè)絕對(duì)路徑(比如 'E:/abc')拖吼,或者是以“/”開頭的路徑,二者都會(huì)返回true
var url1 = path.isAbsolute('../testFiles/secLayer');
var url2 = path.isAbsolute('./join.js');
var url3 = path.isAbsolute('temp');
var url4 = path.isAbsolute('/temp/../..');
var url5 = path.isAbsolute('E:/github/nodeAPI/abc/efg');
var url6 = path.isAbsolute('///temp123');
console.log('url1:',url1); // false
console.log('url2:',url2); // false
console.log('url3:',url3); // false
console.log('url4:',url4); // true
console.log('url5:',url5); // true
console.log('url6:',url6); // true
path.dirname(p)
返回路徑中文件夾的路徑
var url1 = path.dirname('/foo/bar/baz/asdf/a.txt');
var url2 = path.dirname('/foo/bar/baz/asdf/');
var url3 = path.dirname('C:/vajoy/test/aaa');
var url4 = path.dirname(__dirname + '/docs/a.txt')
console.log('url1:',url1); // /foo/bar/baz/asdf
console.log('url2:',url2); // /foo/bar/baz
console.log('url3:',url3); // C:/vajoy/test
console.log(url4);// D:\mobileWeb\temp\test/docs
path.basename(p, [ext])
返回路徑中的最后一部分(通常為文件名)这吻,類似于Unix 的 basename 命令吊档。 ext 為需要截掉的尾綴內(nèi)容
var url1 = path.basename('/foo/bar/baz/asdf/a.txt');
var url2 = path.basename('/foo/bar/baz/asdf/a.txt','.txt');
var url3 = path.basename('/foo/bar/baz/asdf/');
var url4 = path.basename('C:/vajoy/test/aaa');
console.log('url1:',url1); // a.txt
console.log('url2:',url2); // a
console.log('url3:',url3); // asdf
console.log('url4:',url4); // aaa
path.extname(p)
返回路徑文件中的擴(kuò)展名(若存在)
var url1 = path.extname('/foo/bar/baz/asdf/a.txt');
var url2 = path.extname('/foo/bar/baz/asdf/a.txt.html');
var url3 = path.extname('/foo/bar/baz/asdf/a.');
var url4 = path.extname('C:/vajoy/test/.');
var url5 = path.extname('C:/vajoy/test/a');
console.log('url1:',url1); // .txt
console.log('url2:',url2); // .html
console.log('url3:',url3); // .
console.log('url4:',url4); //
console.log('url5:',url5); //
path.parse(pathString)
返回路徑字符串的對(duì)象
var url1 = path.parse('/foo/bar/baz/asdf/a.txt');
url1: {
root: '/',//根目錄
dir: '/foo/bar/baz/asdf',//文件所在目錄
base: 'a.txt',//文件名,輸出文件名稱以base為準(zhǔn),base為空唾糯,則不輸出文件名
ext: '.txt',//文件擴(kuò)展名
name: 'a',//文件名稱, 不含擴(kuò)展名(name返回的是文件名或最后文件夾名)
}
var url2=path.parse('C:\\path\\dir\\');
{ root: 'C:\\',
dir: 'C:\\path',
base: 'dir',
ext: '',
name: 'dir'
}
var url3=path.format({
root:'f:',
dir:'f:\\dir1\\dir2',
name:'file',
base:'file.nanme',
ext:'.txt'
});
//f:\dir1\dir2\file.nanme
var url3=path.format({
root:'f:',
dir:'f:\\dir1\\dir2',
name:'file',
ext:'.txt'
});
//f:\dir1\dir2\
path.format(pathObject)
從對(duì)象中返回路徑字符串怠硼,和 path.parse 相反
var pathObj = {
root: '/',
dir: '/foo/bar/baz/asdf',
base: 'a.txt',
ext: '.txt',
name: 'a'
}
var url1 = path.format(pathObj);
console.log('url1:',url1);//url1: /foo/bar/baz/asdf\a.txt
path.sep
返回對(duì)應(yīng)平臺(tái)下的文件夾分隔符,win下為''趾断,nix下為'/'*
var url1 = path.sep;
var url2 = 'foo\\bar\\baz'.split(path.sep);
var url3 = 'foo/bar/baz'.split(path.sep);
console.log('url1:',url1); // win下為\拒名,*nix下為/
console.log('url2:',url2); // [ 'foo', 'bar', 'baz' ]?
console.log('url3:',url3); // win下返回[ 'foo/bar/baz' ],但在*nix系統(tǒng)下會(huì)返回[ 'foo', 'bar', 'baz' ]
path.delimiter
返回對(duì)應(yīng)平臺(tái)下的路徑分隔符芋酌,win下為';'增显,nix下為':'*
var env = process.env.PATH; //當(dāng)前系統(tǒng)的環(huán)境變量PATH
var url1 = env.split(path.delimiter);
console.log(path.delimiter);
//win下為“;”,*nix下為“:”
console.log('env:',env);
// C:\ProgramData\Oracle\Java\javapath;C:\Program Files (x86)\Intel\iCLS Client\;
console.log('url1:',url1);
// ['C:\ProgramData\Oracle\Java\javapath','C:\Program Files (x86)\Intel\iCLS Client\']
http 網(wǎng)絡(luò)請(qǐng)求模塊
推薦文章
fs 文件系統(tǒng)操作模塊
模塊簡(jiǎn)介
nodejs path 模塊提供了一些用于處理文件系統(tǒng)的小工具脐帝,我們可以通過(guò)如下方式引用它
var path = require("fs")
同步&&異步API
使用require('fs')
載入fs模塊同云,模塊中所有方法都有同步和異步兩種形式。
異步方法中回調(diào)函數(shù)的第一個(gè)參數(shù)總是留給異常參數(shù)(exception)堵腹,如果方法成功完成炸站,該參數(shù)為null或undefined。
fs.readFile('./test.txt', function(err, data) {
if (err) throw err;
console.log('文件內(nèi)容:'+ data);
});
同步寫法疚顷,一般都是在異步方法名后拼接Sycn
字符串旱易,表示是同步方法
var data = fs.readFileSync('./test.txt');
console.log('文件內(nèi)容:'+ data);
同步方法執(zhí)行完并返回結(jié)果后禁偎,才能執(zhí)行后續(xù)的代碼。而異步方法采用回調(diào)函數(shù)接收返回結(jié)果阀坏,可以立即執(zhí)行后續(xù)代碼如暖。下面的代碼演示,都已異步邏輯為主忌堂。
fs.readFile
/**
* filename, 必選參數(shù)盒至,文件名
* [options],可選參數(shù),可指定flag(文件操作選項(xiàng)士修,如r+ 讀寫枷遂;w+ 讀寫,文件不存在則創(chuàng)建)及encoding屬性
* callback 讀取文件后的回調(diào)函數(shù)棋嘲,參數(shù)默認(rèn)第一個(gè)err,第二個(gè)data 數(shù)據(jù)
*/
fs.readFile(__dirname + '/test.txt', {flag: 'r+', encoding: 'utf8'}, function (err, data) {
if(err) throw err;
console.log(data);
});
fs.writeFile
var w_data = '這是一段通過(guò)fs.writeFile函數(shù)寫入的內(nèi)容酒唉;\r\n';
//w_data = new Buffer(w_data);//可以將字符串轉(zhuǎn)換成Buffer類型
/**
* filename, 必選參數(shù),文件名
* data, 寫入的數(shù)據(jù)沸移,可以字符或一個(gè)Buffer對(duì)象
* [options],flag,mode(權(quán)限),encoding
* callback 讀取文件后的回調(diào)函數(shù)黔州,參數(shù)默認(rèn)第一個(gè)err,第二個(gè)data 數(shù)據(jù)
*/
fs.writeFile(__dirname + '/test.txt', w_data, {flag: 'a'}, function (err) {
if(err) throw err;
console.log('寫入成功');
});
{flag: 'a'}
加上這個(gè)參數(shù),內(nèi)容將會(huì)被以追加方式寫入文件阔籽,不加上這個(gè)參數(shù)則會(huì)先清空內(nèi)容,再寫入數(shù)據(jù)
fs.open(filename, flags, [mode], callback);
/**
* filename, 必選參數(shù)牲蜀,文件名
* flags, 操作標(biāo)識(shí)笆制,如"r",讀方式打開
* [mode],權(quán)限,如777涣达,表示任何用戶讀寫可執(zhí)行
* callback 打開文件后回調(diào)函數(shù)在辆,參數(shù)默認(rèn)第一個(gè)err,第二個(gè)fd為一個(gè)整數(shù),表示打開文件返回的文件描述符度苔,window中又稱文件句柄
*/
fs.open(__dirname + '/test.txt', 'r', '0666', function (err, fd) {
console.log(fd);
});
fs.read(fd, buffer, offset, length, position, callback);
講文件內(nèi)容讀入緩存區(qū)
/**
* fd, 使用fs.open打開成功后返回的文件描述符
* buffer, 一個(gè)Buffer對(duì)象匆篓,v8引擎分配的一段內(nèi)存
* offset, 整數(shù),向緩存區(qū)中寫入時(shí)的初始位置寇窑,以字節(jié)為單位
* length, 整數(shù)鸦概,讀取文件的長(zhǎng)度
* position, 整數(shù),讀取文件初始位置甩骏;文件大小以字節(jié)為單位
* callback(err, bytesRead, buffer), 讀取執(zhí)行完成后回調(diào)函數(shù)窗市,bytesRead實(shí)際讀取字節(jié)數(shù),被讀取的緩存區(qū)對(duì)象
*/
fs.open(__dirname + '/test.txt', 'r', function (err, fd) {
if(err) {
console.error(err);
return;
} else {
var buffer = new Buffer(255);
console.log(buffer.length);
//每一個(gè)漢字utf8編碼是3個(gè)字節(jié)饮笛,英文是1個(gè)字節(jié)
fs.read(fd, buffer, 0, 9, 3, function (err, bytesRead, buffer) {
if(err) {
throw err;
} else {
console.log(bytesRead);
console.log(buffer.slice(0, bytesRead).toString());
//讀取完后咨察,再使用fd讀取時(shí),基點(diǎn)是基于上次讀取位置計(jì)算福青;
fs.read(fd, buffer, 0, 9, null, function (err, bytesRead, buffer) {
console.log(bytesRead);
console.log(buffer.slice(0, bytesRead).toString());
});
}
});
}
});
fs.write(fd, buffer, offset, length, position, callback);
寫文件摄狱,將緩沖區(qū)內(nèi)數(shù)據(jù)寫入使用fs.open打開的文件
/**
* fd, 使用fs.open打開成功后返回的文件描述符
* buffer, 一個(gè)Buffer對(duì)象脓诡,v8引擎分配的一段內(nèi)存
* offset, 整數(shù),從緩存區(qū)中讀取時(shí)的初始位置媒役,以字節(jié)為單位
* length, 整數(shù)祝谚,從緩存區(qū)中讀取數(shù)據(jù)的字節(jié)數(shù)
* position, 整數(shù),寫入文件初始位置刊愚;
* callback(err, written, buffer), 寫入操作執(zhí)行完成后回調(diào)函數(shù)踊跟,written實(shí)際寫入字節(jié)數(shù),buffer被讀取的緩存區(qū)對(duì)象
*/
fs.open(__dirname + '/test.txt', 'a', function (err, fd) {
if(err) {
console.error(err);
return;
} else {
var buffer = new Buffer('寫入文件數(shù)據(jù)內(nèi)容');
//寫入'入文件'三個(gè)字
fs.write(fd, buffer, 3, 9, 12, function (err, written, buffer) {
if(err) {
console.log('寫入文件失敗');
console.error(err);
return;
} else {
console.log(buffer.toString());
//寫入'數(shù)據(jù)內(nèi)'三個(gè)字
fs.write(fd, buffer, 12, 9, null, function (err, written, buffer) {
console.log(buffer.toString());
// 使用fs.write寫入文件時(shí)鸥诽,操作系統(tǒng)是將數(shù)據(jù)讀到內(nèi)存商玫,再把數(shù)據(jù)寫入到文件中,所以當(dāng)數(shù)據(jù)讀完時(shí)并不代表數(shù)據(jù)已經(jīng)寫完牡借,因?yàn)橛幸徊糠诌€可能在內(nèi)在緩沖區(qū)內(nèi)拳昌。
// 因此可以使用fs.fsync方法將內(nèi)存中數(shù)據(jù)寫入文件,刷新內(nèi)存緩沖區(qū)钠龙;
fs.fsync(fd);
fs.close(fd);
})
}
});
}
});
fs.mkdir(path, [mode], callback)
創(chuàng)建目錄
/**
* path, 被創(chuàng)建目錄的完整路徑及目錄名炬藤;
* [mode], 目錄權(quán)限,默認(rèn)0777
* [callback(err)], 創(chuàng)建完目錄回調(diào)函數(shù),err錯(cuò)誤對(duì)象
*/
fs.mkdir(__dirname + '/fsDir', function (err) {
if(err)
throw err;
console.log('創(chuàng)建目錄成功')
});
fs.readdir(path, callback)
讀取目錄
/**
* path, 要讀取目錄的完整路徑及目錄名碴里;
* [callback(err, files)], 讀完目錄回調(diào)函數(shù)沈矿;err錯(cuò)誤對(duì)象,files數(shù)組咬腋,存放讀取到的目錄中的所有文件名
*/
fs.readdir(__dirname + '/fsDir/', function (err, files) {
if(err) {
console.error(err);
return;
} else {
files.forEach(function (file) {
var filePath = path.normalize(__dirname + '/fsDir/' + file);
fs.stat(filePath, function (err, stat) {
if(stat.isFile()) {
console.log(filePath + ' is: ' + 'file');
}
if(stat.isDirectory()) {
console.log(filePath + ' is: ' + 'dir');
}
});
});
}
});
fs.stat(path, callback);
查看文件與目錄信息
fs.stat(__dirname + '/test.txt', function (err, stat) {
console.log('訪問(wèn)時(shí)間: ' + stat.atime.toString() + '; \n修改時(shí)間:' + stat.mtime);
console.log(stat.mode);
})
fs.exists(path, callback);
查看文件與目錄是否存在
/**
* path, 要查看目錄/文件的完整路徑及名羹膳;
* [callback(exists)], 操作完成回調(diào)函數(shù);exists true存在根竿,false表示不存在
*/
fs.exists(__dirname + '/test', function (exists) {
var retTxt = exists ? retTxt = '文件存在' : '文件不存在';
console.log(retTxt);
});
fs.rename(oldPath, newPath, callback);
移動(dòng)/重命名文件或目錄
/**
* oldPath, 原目錄/文件的完整路徑及名陵像;
* newPath, 新目錄/文件的完整路徑及名;如果新路徑與原路徑相同寇壳,而只文件名不同醒颖,則是重命名
* [callback(err)], 操作完成回調(diào)函數(shù);err操作失敗對(duì)象
*/
fs.rename(__dirname + '/test', __dirname + '/fsDir', function (err) {
if(err) {
console.error(err);
return;
}
console.log('重命名成功')
});
fs.rmdir(path, callback);
刪除空目錄
/**
* path, 目錄的完整路徑及目錄名壳炎;
* [callback(err)], 操作完成回調(diào)函數(shù)泞歉;err操作失敗對(duì)象
*/
fs.mkdir(__dirname + '/test', function(err){
fs.rmdir(__dirname + '/test', function (err) {
if(err) {
console.log('刪除空目錄失敗,可能原因:1匿辩、目錄不存在疏日,2、目錄不為空')
console.error(err);
return;
}
console.log('刪除空目錄成功!');
});
})
fs.watchFile(filename, [options], listener);
對(duì)文件進(jìn)行監(jiān)視撒汉,并且在監(jiān)視到文件被修改時(shí)執(zhí)行處理
/**
* filename, 完整路徑及文件名沟优;
* [options], persistent true表示持續(xù)監(jiān)視,不退出程序睬辐;interval 單位毫秒挠阁,表示每隔多少毫秒監(jiān)視一次文件
* listener, 文件發(fā)生變化時(shí)回調(diào)宾肺,有兩個(gè)參數(shù):curr為一個(gè)fs.Stat對(duì)象,被修改后文件侵俗,prev,一個(gè)fs.Stat對(duì)象锨用,表示修改前對(duì)象
*/
fs.watchFile(__dirname + '/test.txt', {interval: 20}, function (curr, prev) {
if(Date.parse(prev.ctime) == 0) {
console.log('文件被創(chuàng)建!');//?
} else if(Date.parse(curr.ctime) == 0) {
console.log('文件被刪除!')
} else if(Date.parse(curr.mtime) != Date.parse(prev.mtime)) {
console.log('文件有修改');
}
});
fs.watchFile(__dirname + '/test.txt', function (curr, prev) {
console.log('這是第二個(gè)watch,監(jiān)視到文件有修改');
});
fs.watch(filename, [options], [listener]);
對(duì)文件或目錄進(jìn)行監(jiān)視,并且在監(jiān)視到修改時(shí)執(zhí)行處理隘谣;
fs.watch返回一個(gè)fs.FSWatcher對(duì)象增拥,擁有一個(gè)close方法,用于停止watch操作寻歧;
當(dāng)fs.watch有文件變化時(shí)掌栅,會(huì)觸發(fā)fs.FSWatcher對(duì)象的change(err, filename)事件,err錯(cuò)誤對(duì)象码泛,filename發(fā)生變化的文件名
/**
* filename, 完整路徑及文件名或目錄名猾封;
* [listener(event, filename], 監(jiān)聽器事件,有兩個(gè)參數(shù):event 為rename表示指定的文件或目錄中有重命名噪珊、刪除或移動(dòng)操作或change表示有修改晌缘,filename表示發(fā)生變化的文件路徑
*/
var fsWatcher = fs.watch(__dirname + '/test', function (event, filename) {
//console.log(event)
});
//console.log(fsWatcher instanceof FSWatcher);
fsWatcher.on('change', function (event, filename) {
console.log(filename + ' 發(fā)生變化')
});
//30秒后關(guān)閉監(jiān)視
setTimeout(function () {
console.log('關(guān)閉')
fsWatcher.close(function (err) {
if(err) {
console.error(err)
}
console.log('關(guān)閉watch')
});
}, 30000);
文件流
/*
* 流,在應(yīng)用程序中表示一組有序的痢站、有起點(diǎn)有終點(diǎn)的字節(jié)數(shù)據(jù)的傳輸手段磷箕;
* Node.js中實(shí)現(xiàn)了stream.Readable/stream.Writeable接口的對(duì)象進(jìn)行流數(shù)據(jù)讀寫;以上接口都繼承自EventEmitter類阵难,因此在讀/寫流不同狀態(tài)時(shí)搀捷,觸發(fā)不同事件;
* 關(guān)于流讀榷嗤:Node.js不斷將文件一小塊內(nèi)容讀入緩沖區(qū),再?gòu)木彌_區(qū)中讀取內(nèi)容氢烘;
* 關(guān)于流寫入:Node.js不斷將流數(shù)據(jù)寫入內(nèi)在緩沖區(qū)怀偷,待緩沖區(qū)滿后再將緩沖區(qū)寫入到文件中;重復(fù)上面操作直到要寫入內(nèi)容寫寫完播玖;
* readFile椎工、read、writeFile蜀踏、write都是將整個(gè)文件放入內(nèi)存而再操作维蒙,而則是文件一部分?jǐn)?shù)據(jù)一部分?jǐn)?shù)據(jù)操作;
*
* -----------------------流讀取-------------------------------------
* 讀取數(shù)據(jù)對(duì)象:
* fs.ReadStream 讀取文件
* http.IncomingMessage 客戶端請(qǐng)求或服務(wù)器端響應(yīng)
* net.Socket Socket端口對(duì)象
* child.stdout 子進(jìn)程標(biāo)準(zhǔn)輸出
* child.stdin 子進(jìn)程標(biāo)準(zhǔn)入
* process.stdin 用于創(chuàng)建進(jìn)程標(biāo)準(zhǔn)輸入流
* Gzip果覆、Deflate颅痊、DeflateRaw 數(shù)據(jù)壓縮
*
* 觸發(fā)事件:
* readable 數(shù)據(jù)可讀時(shí)
* data 數(shù)據(jù)讀取后
* end 數(shù)據(jù)讀取完成時(shí)
* error 數(shù)據(jù)讀取錯(cuò)誤時(shí)
* close 關(guān)閉流對(duì)象時(shí)
*
* 讀取數(shù)據(jù)的對(duì)象操作方法:
* read 讀取數(shù)據(jù)方法
* setEncoding 設(shè)置讀取數(shù)據(jù)的編
* pause 通知對(duì)象眾目停止觸發(fā)data事件
* resume 通知對(duì)象恢復(fù)觸發(fā)data事件
* pipe 設(shè)置數(shù)據(jù)通道,將讀入流數(shù)據(jù)接入寫入流局待;
* unpipe 取消通道
* unshift 當(dāng)流數(shù)據(jù)綁定一個(gè)解析器時(shí)斑响,此方法取消解析器
*
* ------------------------流寫入-------------------------------------
* 寫數(shù)據(jù)對(duì)象:
* fs.WriteStream 寫入文件對(duì)象
* http.clientRequest 寫入HTTP客戶端請(qǐng)求數(shù)據(jù)
* http.ServerResponse 寫入HTTP服務(wù)器端響應(yīng)數(shù)據(jù)
* net.Socket 讀寫TCP流或UNIX流菱属,需要connection事件傳遞給用戶
* child.stdout 子進(jìn)程標(biāo)準(zhǔn)輸出
* child.stdin 子進(jìn)程標(biāo)準(zhǔn)入
* Gzip、Deflate舰罚、DeflateRaw 數(shù)據(jù)壓縮
*
* 寫入數(shù)據(jù)觸發(fā)事件:
* drain 當(dāng)write方法返回false時(shí)纽门,表示緩存區(qū)中已經(jīng)輸出到目標(biāo)對(duì)象中,可以繼續(xù)寫入數(shù)據(jù)到緩存區(qū)
* finish 當(dāng)end方法調(diào)用营罢,全部數(shù)據(jù)寫入完成
* pipe 當(dāng)用于讀取數(shù)據(jù)的對(duì)象的pipe方法被調(diào)用時(shí)
* unpipe 當(dāng)unpipe方法被調(diào)用
* error 當(dāng)發(fā)生錯(cuò)誤
*
* 寫入數(shù)據(jù)方法:
* write 用于寫入數(shù)據(jù)
* end 結(jié)束寫入赏陵,之后再寫入會(huì)報(bào)錯(cuò);
*/
fs.createReadStream(path, [options])
創(chuàng)建讀取流
/**
* path 文件路徑
* [options] flags:指定文件操作蝙搔,默認(rèn)'r',讀操作;encoding,指定讀取流編碼能颁;autoClose, 是否讀取完成后自動(dòng)關(guān)閉杂瘸,默認(rèn)true;start指定文件開始讀取位置伙菊;end指定文件開始讀結(jié)束位置
*/
var rs = fs.createReadStream(__dirname + '/test.txt', {start: 0, end: 2});
//open是ReadStream對(duì)象中表示文件打開時(shí)事件败玉,
rs.on('open', function (fd) {
console.log('開始讀取文件');
});
rs.on('data', function (data) {
console.log(data.toString());
});
rs.on('end', function () {
console.log('讀取文件結(jié)束')
});
rs.on('close', function () {
console.log('文件關(guān)閉');
});
rs.on('error', function (err) {
console.error(err);
});
//暫停和回復(fù)文件讀取镜硕;
rs.on('open', function () {
console.log('開始讀取文件');
});
rs.pause();
rs.on('data', function (data) {
console.log(data.toString());
});
setTimeout(function () {
rs.resume();
}, 2000);
fs.createWriteStream(path, [options])
創(chuàng)建寫入流
/**
* path 文件路徑
* [options] flags:指定文件操作运翼,默認(rèn)'w',;encoding,指定讀取流編碼兴枯;start指定寫入文件的位置
*/
/* ws.write(chunk, [encoding], [callback]);
* chunk, 可以為Buffer對(duì)象或一個(gè)字符串血淌,要寫入的數(shù)據(jù)
* [encoding], 編碼
* [callback], 寫入后回調(diào)
*/
/* ws.end([chunk], [encoding], [callback]);
* [chunk], 要寫入的數(shù)據(jù)
* [encoding], 編碼
* [callback], 寫入后回調(diào)
*/
var ws = fs.createWriteStream(__dirname + '/test.txt', {start: 0});
var buffer = new Buffer('我也喜歡你');
ws.write(buffer, 'utf8', function (err, buffer) {
console.log(arguments);
console.log('寫入完成,回調(diào)函數(shù)沒有參數(shù)')
});
//最后再寫入的內(nèi)容
ws.end('再見');
//使用流完成復(fù)制文件操作
var rs = fs.createReadStream(__dirname + '/test.txt')
var ws = fs.createWriteStream(__dirname + '/test/test.txt');
rs.on('data', function (data) {
ws.write(data)
});
ws.on('open', function (fd) {
console.log('要寫入的數(shù)據(jù)文件已經(jīng)打開财剖,文件描述符是: ' + fd);
});
rs.on('end', function () {
console.log('文件讀取完成');
ws.end('完成', function () {
console.log('文件全部寫入完成')
});
});
//關(guān)于WriteStream對(duì)象的write方法返回一個(gè)布爾類型悠夯,當(dāng)緩存區(qū)中數(shù)據(jù)全部寫滿時(shí),返回false;
//表示緩存區(qū)寫滿躺坟,并將立即輸出到目標(biāo)對(duì)象中
//第一個(gè)例子
var ws = fs.createWriteStream(__dirname + '/test/test.txt');
for (var i = 0; i < 10000; i++) {
var w_flag = ws.write(i.toString());
//當(dāng)緩存區(qū)寫滿時(shí)沦补,輸出false
console.log(w_flag);
}
//第二個(gè)例子
var ws = fs.createWriteStream(__dirname + '/test/untiyou.mp3');
var rs = fs.createReadStream(__dirname + '/test/Until You.mp3');
rs.on('data', function (data) {
var flag = ws.write(data);
console.log(flag);
});
//系統(tǒng)緩存區(qū)數(shù)據(jù)已經(jīng)全部輸出觸發(fā)drain事件
ws.on('drain', function () {
console.log('系統(tǒng)緩存區(qū)數(shù)據(jù)已經(jīng)全部輸出。')
});
rs.pipe(destination, [options]);
管道pipe實(shí)現(xiàn)流讀寫
//rs.pipe(destination, [options]);
/**
* destination 必須一個(gè)可寫入流數(shù)據(jù)對(duì)象
* [opations] end 默認(rèn)為true咪橙,表示讀取完成立即關(guān)閉文件夕膀;
*/
var rs = fs.createReadStream(__dirname + '/test/Until You.mp3');
var ws = fs.createWriteStream(__dirname + '/test/untiyou.mp3');
rs.pipe(ws);
rs.on('data', function (data) {
console.log('數(shù)據(jù)可讀')
});
rs.on('end', function () {
console.log('文件讀取完成');
//ws.end('再見')
});
推薦文章
url 處理模塊
引用
var url = require("url");
URL 的組成介紹
對(duì)于一個(gè) URL 字符串,其組成部分會(huì)有所有不同美侦,其中有些部分只有在URL字符串中存在時(shí)产舞,對(duì)應(yīng)字段才會(huì)出現(xiàn)在解析后對(duì)象中。以下是一個(gè) URL 例子:
http://user:pass@host.com:8080/p/a/t/h?query=string#hash
href: 解析前的完整原始 URL菠剩,協(xié)議名和主機(jī)名已轉(zhuǎn)為小寫
例如: 'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'
protocol: 請(qǐng)求協(xié)議易猫,小寫
例如: 'http:'
slashes: 協(xié)議的“:”號(hào)后是否有“/”
例如: true or false
auth: URL中的認(rèn)證信息
例如: 'user:pass'
host: URL主機(jī)名,包括端口信息具壮,小寫
例如: 'host.com:8080'
hostname: 主機(jī)名擦囊,小寫
例如: 'host.com'
port: 主機(jī)的端口號(hào)
例如: '8080'
path: pathname 和 search的合集
例如: '/p/a/t/h?query=string'
pathname: URL中路徑
例如: '/p/a/t/h'
search: 查詢對(duì)象违霞,即:queryString,包括之前的問(wèn)號(hào)“?”
例如: '?query=string'
query: 查詢字符串中的參數(shù)部分(問(wèn)號(hào)后面部分字符串)瞬场,或者使用 querystring.parse() 解析后返回的對(duì)象
例如: 'query=string' or {'query':'string'}
hash: 錨點(diǎn)部分(即:“#”及其后的部分)
例如: '#hash'
url.parse(urlStr[, parseQueryString][, slashesDenoteHost])
將URL字符串轉(zhuǎn)換為JSON對(duì)象
var urlString = 'http://user:pass@host.com:8080/p/a/t/h?query=string#hash';
var result = url.parse(urlString);
console.log(result);
//輸出結(jié)果如下
{ protocol: 'http:',
slashes: true,
auth: 'user:pass',
host: 'host.com:8080',
port: '8080',
hostname: 'host.com',
hash: '#hash',
search: '?query=string',
query: 'query=string',
pathname: '/p/a/t/h',
path: '/p/a/t/h?query=string',
href: 'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'
}
//第二個(gè)可選參數(shù)設(shè)置為true時(shí)买鸽,會(huì)使用querystring模塊來(lái)解析URL中德查詢字符串部分,默認(rèn)為 false贯被。
var result1 = url.parse(urlString, true);
console.log(result1);
//輸出結(jié)果如下
{ protocol: 'http:',
slashes: true,
auth: 'user:pass',
host: 'host.com:8080',
port: '8080',
hostname: 'host.com',
hash: '#hash',
search: '?query=string',
query: {query:"string"},
pathname: '/p/a/t/h',
path: '/p/a/t/h?query=string',
href: 'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'
}
url.format(urlObj)
用于格式化URL對(duì)象眼五。輸入一個(gè) URL 對(duì)象,返回格式化后的 URL 字符串彤灶。示例如下
var urlObj = {
protocol: 'http:',
slashes: true,
hostname: 'jianshu.com',
port: 80,
hash: '#hash',
search: '?query=string',
path: '/nodejs?query=string'
}
var result = url.format(urlObj);
console.log(result);
//輸出結(jié)果如下
http://jianshu.com:80?query=string#hash
/*
*傳入的URL對(duì)象會(huì)做以下處理:
*
*href 屬性會(huì)被忽略
*protocol無(wú)論是否有末尾的 : (冒號(hào))看幼,會(huì)同樣的處理
**這些協(xié)議包括 http, https, ftp, gopher, file 后綴是 :// (冒號(hào)-斜杠-斜杠).
**所有其他的協(xié)議如 mailto, xmpp, aim, sftp, foo, 等 會(huì)加上后綴 : (冒號(hào))
*auth 如果有將會(huì)出現(xiàn).
*host 優(yōu)先使用,將會(huì)替代 hostname 和port
*hostname 如果 host 屬性沒被定義幌陕,則會(huì)使用此屬性.
*port 如果 host 屬性沒被定義诵姜,則會(huì)使用此屬性.
*pathname 將會(huì)同樣處理無(wú)論結(jié)尾是否有/ (斜杠)
*search 將會(huì)替代 query屬性
*query (object類型; 詳細(xì)請(qǐng)看 querystring) 如果沒有 search,將會(huì)使用此屬性.
*search 無(wú)論前面是否有 ? (問(wèn)號(hào)),都會(huì)同樣的處理
*hash無(wú)論前面是否有# (井號(hào), 錨點(diǎn))搏熄,都會(huì)同樣處理
*/
url.resolve(from, to)
用于拼接路徑
url.resolve('/one/two/three', 'four') // '/one/two/four'
url.resolve('http://example.com/', '/one') // 'http://example.com/one'
url.resolve('http://example.com/one', '/two') // 'http://example.com/two'
query string 參數(shù)處理模塊
引用
var querystring = require('querystring')
querystring.stringify(obj, [sep], [eq])
對(duì)象格式化成參數(shù)字符串 ,obj就是要格式化的對(duì)象,必選參數(shù);[sep]指分隔符 默認(rèn)'&'; [eq]指分配符 默認(rèn)'='
var querystring = require('querystring')
var param = {name:"feng",age:"33"};
var paramStr1 = querystring.stringify(param);
console.log(paramStr1);//name=feng&age=33
var paramStr2 = querystring.stringify(param,'$','-');
console.log(paramStr2);//name-feng$age-33
本方法會(huì)自動(dòng)編碼漢字
querystring.parse(str, [sep], [eq], [options])
參數(shù)字符串格式化成對(duì)象
var paramStr1 = 'name=feng&age=33';
var paramStr2 = 'name-feng$age-33';
var param1 = querystring.parse(paramStr1);
console.log(param1);//{ name: 'feng', age: '33' }
var param2 = querystring.parse(paramStr2, '$', '-');
console.log(param2);//{ name: 'feng', age: '33' }
querystring.escape
參數(shù)編碼
var param = "name=阿峰&age=33";
console.log(querystring.escape(param));
//name%3D%E9%98%BF%E5%B3%B0%26age%3D33
querystring.unescape
參數(shù)解碼
var param = "name=阿峰&age=33";
console.log(querystring.unescape(querystring.escape(param)));
//name=阿峰&age=33
os
引用
var os = require('os');
常用函數(shù)
//cpu架構(gòu)
os.arch();
//操作系統(tǒng)內(nèi)核
os.type();
//操作系統(tǒng)平臺(tái)
os.platform();
//系統(tǒng)開機(jī)時(shí)間
os.uptime();
//主機(jī)名
os.hostname();
//主目錄
os.homedir();
//內(nèi)存
os.totalmem();//總內(nèi)存
os.freemem();// 空閑內(nèi)存
//cpu
const cpus = os.cpus();
cpus.forEach((cpu,idx,arr)=>{
var times = cpu.times;
console.log(`cpu${idx}:`);
console.log(`型號(hào):${cpu.model}`);
console.log(`頻率:${cpu.speed}MHz`);
console.log(`使用率:${((1-times.idle/(times.idle+times.user+times.nice+times.sys+times.irq))*100).toFixed(2)}%`);
});
//網(wǎng)卡
const networksObj = os.networkInterfaces();
for(let nw in networksObj){
let objArr = networksObj[nw];
console.log(`\r\n${nw}:`);
objArr.forEach((obj,idx,arr)=>{
console.log(`地址:${obj.address}`);
console.log(`掩碼:${obj.netmask}`);
console.log(`物理地址:${obj.mac}`);
console.log(`協(xié)議族:${obj.family}`);
});
}
stream
為什么使用流
nodejs的fs模塊并沒有提供一個(gè)copy的方法棚唆,但我們可以很容易的實(shí)現(xiàn)一個(gè),比如:
var source = fs.readFileSync('/path/to/source', {encoding: 'utf8'});
fs.writeFileSync('/path/to/dest', source);
上面的這段代碼并沒有什么問(wèn)題心例,但是在每次請(qǐng)求時(shí)宵凌,我們都會(huì)把整個(gè)源文件讀入到內(nèi)存中,然后再把結(jié)果返回給客戶端止后。想想看瞎惫,如果源文件非常大,在響應(yīng)大量用戶的并發(fā)請(qǐng)求時(shí)译株,程序可能會(huì)消耗大量的內(nèi)存瓜喇,這樣很可能會(huì)造成用戶連接緩慢的問(wèn)題。
理想的方法應(yīng)該是讀一部分歉糜,寫一部分乘寒,不管文件有多大,只要時(shí)間允許现恼,總會(huì)處理完成,這里就需要用到流的概念黍檩。
上面的文件復(fù)制可以簡(jiǎn)單實(shí)現(xiàn)一下:
var fs = require('fs');
var readStream = fs.createReadStream('/path/to/source');
var writeStream = fs.createWriteStream('/path/to/dest');
readStream.on('data', function(chunk) { // 當(dāng)有數(shù)據(jù)流出時(shí)叉袍,寫入數(shù)據(jù)
writeStream.write(chunk);
});
readStream.on('end', function() { // 當(dāng)沒有數(shù)據(jù)時(shí),關(guān)閉數(shù)據(jù)流
writeStream.end();
});
上面的寫法有一些問(wèn)題刽酱,如果寫入的速度跟不上讀取的速度喳逛,有可能導(dǎo)致數(shù)據(jù)丟失。正常的情況應(yīng)該是棵里,寫完一段润文,再讀取下一段姐呐,如果沒有寫完的話,就讓讀取流先暫停典蝌,等寫完再繼續(xù)曙砂,于是代碼可以修改為:
var fs = require('fs');
var readStream = fs.createReadStream('/path/to/source');
var writeStream = fs.createWriteStream('/path/to/dest');
readStream.on('data', function(chunk) { // 當(dāng)有數(shù)據(jù)流出時(shí),寫入數(shù)據(jù)
if (writeStream.write(chunk) === false) { // 如果沒有寫完骏掀,暫停讀取流
readStream.pause();
}
});
writeStream.on('drain', function() { // 寫完后鸠澈,繼續(xù)讀取
readStream.resume();
});
readStream.on('end', function() { // 當(dāng)沒有數(shù)據(jù)時(shí),關(guān)閉數(shù)據(jù)流
writeStream.end();
});
或者使用更直接的pipe
// pipe自動(dòng)調(diào)用了data,end等事件
fs.createReadStream('/path/to/source').pipe(fs.createWriteStream('/path/to/dest'));
下面是一個(gè)完整的復(fù)制文件的過(guò)程
var fs = require('fs'),
path = require('path'),
out = process.stdout;
var filePath = 'Users/feng/Documents/something/kobe.gif';
var readStream = fs.createReadStream(filePath);
var writeStream = fs.createWriteStream('file.gif');
var stat = fs.statSync(filePath);
var totalSize = stat.size;
var passedLength = 0;
var lastSize = 0;
var startTime = Date.now();
readStream.on('data', function(chunk) {
passedLength += chunk.length;
if (writeStream.write(chunk) === false) {
readStream.pause();
}
});
readStream.on('end', function() {
writeStream.end();
});
writeStream.on('drain', function() {
readStream.resume();
});
setTimeout(function show() {
var percent = Math.ceil((passedLength / totalSize) * 100);
var size = Math.ceil(passedLength / 1000000);
var diff = size - lastSize;
lastSize = size;
out.clearLine();
out.cursorTo(0);
out.write('已完成' + size + 'MB, ' + percent + '%, 速度:' + diff + 'MB/s');
if (passedLength < totalSize) {
setTimeout(show, 500);
} else {
var endTime = Date.now();
console.log();
console.log('共用時(shí):' + (endTime - startTime) / 1000 + '秒截驮。');
}
}, 500);
Readable流
fs.createReadStream(path[, options])
用來(lái)打開一個(gè)可讀的文件流笑陈,它返回一個(gè)fs.ReadStream
對(duì)象。path參數(shù)指定文件的路徑葵袭,可選的options是一個(gè)JS對(duì)象涵妥,可以指定一些選項(xiàng),類似下面這樣:
{ flags: 'r',
encoding: 'utf8',
fd: null,
mode: 0666,
autoClose: true
}
options的flags屬性指定用什么模式打開文件:
- ’w’代表寫坡锡,’r’代表讀蓬网,類似的還有’r+’、’w+’娜氏、’a’等拳缠,與Linux下的open函數(shù)接受的讀寫模式類似。
- encoding指定打開文件時(shí)使用編碼格式贸弥,默認(rèn)就是“utf8”窟坐,你還可以為它指定”ascii”或”base64”。
- fd屬性默認(rèn)為null绵疲,當(dāng)你指定了這個(gè)屬性時(shí)哲鸳,createReadableStream會(huì)根據(jù)傳入的fd創(chuàng)建一個(gè)流,忽略path盔憨。另外你要是想讀取一個(gè)文件的特定區(qū)域徙菠,可以配置start、end屬性郁岩,指定起始和結(jié)束(包含在內(nèi))的字節(jié)偏移婿奔。
- autoClose屬性為true(默認(rèn)行為)時(shí),當(dāng)發(fā)生錯(cuò)誤或文件讀取結(jié)束時(shí)會(huì)自動(dòng)關(guān)閉文件描述符问慎。
Readable還提供了一些函數(shù)萍摊,我們可以用它們讀取或操作流:
- read([size]):如果你給read方法傳遞了一個(gè)制定大小作為參數(shù),那它會(huì)返回指定數(shù)量的數(shù)據(jù)如叼,如果數(shù)據(jù)不足冰木,就會(huì)返回null。如果你不給read方法傳參,它會(huì)返回內(nèi)部緩沖區(qū)里的所有數(shù)據(jù)踊沸,如果沒有數(shù)據(jù)歇终,會(huì)返回null,此時(shí)有可能說(shuō)明遇到了文件末尾逼龟。read返回的數(shù)據(jù)可能是Buffer對(duì)象评凝,也可能是String對(duì)象。
- setEncoding(encoding):給流設(shè)置一個(gè)編碼格式审轮,用于解碼讀到的數(shù)據(jù)肥哎。調(diào)用此方法后睛蛛,read([size])方法返回String對(duì)象镜撩。
- pause():暫筒腔辏可讀流痊夭,不再發(fā)出data事件
- resume():恢復(fù)可讀流智亮,繼續(xù)發(fā)出data事件
- pipe(destination,[options]):把這個(gè)可讀流的輸出傳遞給destination指定的Writable流克懊,兩個(gè)流組成一個(gè)管道洋丐。options是一個(gè)JS對(duì)象豪诲,這個(gè)對(duì)象有一個(gè)布爾類型的end屬性吊圾,默認(rèn)值為true达椰,當(dāng)end為true時(shí),Readable結(jié)束時(shí)自動(dòng)結(jié)束Writable项乒。注意啰劲,我們可以把一個(gè)Readable與若干Writable連在一起,組成多個(gè)管道檀何,每一個(gè)Writable都能得到同樣的數(shù)據(jù)蝇裤。這個(gè)方法返回destination,如果destination本身又是Readable流频鉴,就可以級(jí)聯(lián)調(diào)用pipe(比如我們?cè)谑褂胓zip壓縮栓辜、解壓縮時(shí)就會(huì)這樣,馬上會(huì)講到)垛孔。
- unpipe([destination]):端口與指定destination的管道藕甩。不傳遞destination時(shí),斷開與這個(gè)可讀流連在一起的所有管道周荐。
Readable流提供了以下事件:
- readable:在數(shù)據(jù)塊可以從流中讀取的時(shí)候發(fā)出狭莱。它對(duì)應(yīng)的處理器沒有參數(shù),可以在處理器里調(diào)用read([size])方法讀取數(shù)據(jù)概作。
- data:有數(shù)據(jù)可讀時(shí)發(fā)出腋妙。它對(duì)應(yīng)的處理器有一個(gè)參數(shù),代表數(shù)據(jù)仆嗦。如果你只想快快地讀取一個(gè)流的數(shù)據(jù)辉阶,給data關(guān)聯(lián)一個(gè)處理器是最方便的辦法先壕。處理器的參數(shù)是Buffer對(duì)象瘩扼,如果你調(diào)用了Readable的setEncoding(encoding)方法谆甜,處理器的參數(shù)就是String對(duì)象。
- end:當(dāng)數(shù)據(jù)被讀完時(shí)發(fā)出集绰。對(duì)應(yīng)的處理器沒有參數(shù)规辱。
- close:當(dāng)?shù)讓拥馁Y源,如文件栽燕,已關(guān)閉時(shí)發(fā)出罕袋。不是所有的Readable流都會(huì)發(fā)出這個(gè)事件。對(duì)應(yīng)的處理器沒有參數(shù)碍岔。
- error:當(dāng)在接收數(shù)據(jù)中出現(xiàn)錯(cuò)誤時(shí)發(fā)出浴讯。對(duì)應(yīng)的處理器參數(shù)是Error的實(shí)例,它的message屬性描述了錯(cuò)誤原因蔼啦,stack屬性保存了發(fā)生錯(cuò)誤時(shí)的堆棧信息榆纽。
一個(gè)基本的可讀流實(shí)例
var fs = require('fs');
var readable = fs.createReadStream('text.js',{
flags: 'r',
encoding: 'utf8',
autoClose: true,
mode: 0666,
});
readable.on('open', function(fd){
console.log('file was opened, fd - ', fd);
});
readable.on('readable', function(){
console.log('received readable');
});
readable.on('data', function(chunk){
console.log('read %d bytes: %s', chunk.length, chunk);
});
readable.on('end', function(){
console.log('read end');
});
readable.on('close', function(){
console.log('file was closed.');
});
readable.on('error', function(err){
console.log('error occured: %s', err.message);
});
Writable
Writable流提供了一個(gè)接口,用來(lái)把數(shù)據(jù)寫入到目的設(shè)備(或內(nèi)存)中捏肢。
Writable提供了一些函數(shù)來(lái)操作流
write(chunk[,encoding][,callback])
可以把數(shù)據(jù)寫入流中奈籽。其中,chunk是待寫入的數(shù)據(jù)鸵赫,是Buffer或String對(duì)象衣屏。這個(gè)參數(shù)是必須的,其它參數(shù)都是可選的辩棒。如果chunk是String對(duì)象狼忱,encoding可以用來(lái)指定字符串的編碼格式,write會(huì)根據(jù)編碼格式將chunk解碼成字節(jié)流再來(lái)寫入盗温。callback是數(shù)據(jù)完全刷新到流中時(shí)會(huì)執(zhí)行的回調(diào)函數(shù)藕赞。write方法返回布爾值,當(dāng)數(shù)據(jù)被完全處理后返回true(不一定是完全寫入設(shè)備哦)卖局。end([chunk] [,encoding][,callback])
方法可以用來(lái)結(jié)束一個(gè)可寫流斧蜕。它的三個(gè)參數(shù)都是可選的。chunk和encoding的含義與write方法類似砚偶。callback是一個(gè)可選的回調(diào)批销,當(dāng)你提供它時(shí),它會(huì)被關(guān)聯(lián)到Writable的finish事件上染坯,這樣當(dāng)finish事件發(fā)射時(shí)它就會(huì)被調(diào)用均芽。
現(xiàn)在我們來(lái)看看Writable公開的事件:
finish: 在end()被調(diào)用、所有數(shù)據(jù)都已被寫入底層設(shè)備后發(fā)射单鹿。對(duì)應(yīng)的處理器函數(shù)沒有參數(shù)掀宋。
pipe: 當(dāng)你在Readable流上調(diào)用pipe()方法時(shí),Writable流會(huì)發(fā)射這個(gè)事件,對(duì)應(yīng)的處理器函數(shù)有一個(gè)參數(shù)劲妙,類型是Readable湃鹊,指向與它連接的那個(gè)Readable流。
unpipe: 當(dāng)你在Readable流上調(diào)用unpipe()方法時(shí)镣奋,Writable流會(huì)發(fā)射這個(gè)事件币呵,對(duì)應(yīng)的處理器函數(shù)有一個(gè)參數(shù),類型是Readable侨颈,指向與剛與它斷開連接的那個(gè)Readable流余赢。
error: 出錯(cuò)時(shí)發(fā)射,對(duì)應(yīng)的處理器函數(shù)的參數(shù)是Error對(duì)象哈垢。
看一個(gè)簡(jiǎn)單實(shí)例
var fs = require('fs');
var writable = fs.createWriteStream('example.txt',{
flags: 'w',
defaultEncoding: 'utf8',
mode: 0666,
});
writable.on('finish', function(){
console.log('write finished');
process.exit(0);
});
writable.on('error', function(err){
console.log('write error - %s', err.message);
});
writable.write('hello 地方', 'utf8');
writable.end();
其他流
略
參考文章
其他系列文章
Nodejs模塊學(xué)習(xí)筆記
極客學(xué)院 nodejs官方文檔