1. 程式人生 > >《node.js權威指南》讀書筆記

《node.js權威指南》讀書筆記

尺寸 完整路徑 dlink eve cat use ring files sym

第一章 node.js介紹

非阻塞型I/O機制

當在訪問數據庫取得搜索結果的時候,在開始訪問數據庫之後,數據庫返回結果之前,存在一段等待時間。
在傳統的單線程處理機制中,在執行了訪問數據庫的代碼之後,整個線程都將暫停下來,等待數據庫返回查詢結果之後才能繼續執行後面的代碼。這是I/O型阻塞
node.js中在執行了訪問數據庫的代碼之後將立即執行其後面的代碼段,把數據庫返回的結果的處理代碼放在回調函數中。這是非阻塞型I/O機制

第三章 node.js中的全局作用域及全局函數

timer.unref()用於取消setTimeout或setInterval函數中指定的回調函數的調用
timer.ref()恢復unref方法取消的回調函數

var testFunction = function(){
    console.log('aaa')
}
var timer = setInterval(testFunction,3000)
//取消定時器對象的回調函數調用
timer.unref() //沒有輸出
//恢復定時器對象的回調函數調用
// timer.ref()//有輸出

在任何模塊文件內部,可以使用__filename變量獲取當前模塊文件名
在任何模塊文件內部,可以使用__dirname變量獲取當前模塊文件所在目錄的完成絕對路徑

EventEmitter類

技術分享圖片

emitter.setMaxListeners(n)
默認情況下,如果為特定事件添加了超過 10 個監聽器,則 EventEmitter 會打印一個警告

emitter.setMaxListeners() 方法可以為指定的 EventEmitter 實例修改限制。 值設為 Infinity(或 0)表示不限制監聽器的數量。

當需要手工觸發某個對象的一個事件時,使用EventEmitter類的emit方法
emitter.emit(event,[arg1],...)

第六章 在Node.js中操作文件系統

在node.js中使用fs模塊來實現所有有關文件及目錄的創建寫入及刪除操作,所有的操作都有同步(有Sync後綴)和異步的方法

文件的完整讀寫

fs.readFile(path,[options],callback)
options參數為一個對象,在該參數值對象中可以使用flag屬性指定對該文件采取什麽操作,默認是‘r’

可指定值如下所示
技術分享圖片
在options參數值中可使用encoding屬性指定使用何種編碼格式來讀取該文件,可指定‘utf8’,‘ascii‘,‘base64‘

var fs = require('fs')
fs.readFile('./test.txt',utf8',function(err,data){
    if(err){
        console.log('read error')
    }else{
        coonsole.log(data.toString())    //將buffer對象轉換為字符串
    }
})

fs.writeFile(path,data,[options],callback)
data參數用於指定需要寫入的內容,可以是一個字符串或一個buffer對象
options參數值為一個對象

var options= {
    flag:'w' //用於指定對該文件采取何種操作,默認'w'
    mode:0666 //用於指定當文件被打開時對該文件的讀寫權限,默認0666(可讀寫)
    encoding:'utf8'//用於指定使用何種編碼格式來寫入該文件
}
var fs = require('fs')
fs.writeFile('./message.txt','這是第一行\r\n這是第二行',function(err){
    if(err){
        console.log('err:',err)
    }else{
        console.log('success')
    }
})

將一個字符串或一個緩沖區的數據追加到一個文件底部時,可以使用fs.appendFile()或者fs.appendFileSync()

var fs = require('fs')
fs.appendFile('./message.txt','\r\n這是追加的數據',function(err){
    if(err){
        console.log('err:',err)
    }else{
        console.log('success')
    }
})

從指定位置處開始讀寫文件

首先需要使用fs模塊中的open方法或者openSync方法打開文件
fs.open(path,flags,[model],callback)

var fs = require('fs')

fs.open('./message.txt','r',function(err,fd){
    if(err){
        console.log('err:',err)
    }else{
        console.log(fd)//文件描述符
    }
})

打開文件後可以在回調函數中使用fs.read()從文件指定位置處讀取文件,也可以使用fs.write()方法從文件的指定處開始寫入數據
read()從文件的指定位置出讀取文件,一直讀取到文件底部然後將讀取到的內容輸出到一個緩沖區

fs.read(fd,buffer,offset,length,position,callback)

fd參數值必須為open方法所使用的回調函數中返回的文件描述符
offset參數用於指定向緩存區中寫入數據的開始寫入位置(以字節為單位)
length參數用於指定從文件中讀取的字節數
position參數用於指定讀取文件時的開始位置

fs.open('./message.txt','r',function (err,fd) {
    var buf = new Buffer(255)
    fs.read(fd,buf,0,9,3,function (err,bytesRead,buffer) {
        console.log(buffer.slice(0,bytesRead).toString())
    })
})

再打開文件之後,可以使用fs.write()或者writeSync()方法從一個緩存區中讀取數據並且從文件的指定出開始寫入數據
fs.write(fd,buffer,offset,length,position,callback)
參數與open方法參數類似

var buf = new Buffer('我喜愛編程')
fs.open('./message.txt','w',function (err,fd) {
    fs.write(fd,buf,3,9,0,function (err,written,buffer) {
        if(err){
            console.log(err)
        }
        console.log('success')
    })
})

在fs模塊中提供close()與closeSync()關閉文件
fs.close(fd,[callback])
在使用write()方法在文件中寫入數據時,操作系統先將該部分數據讀取到內存中,在把數據寫入到文件中,當數據讀完並不代表數據已經寫入,此時調用close()方法會將部分數據丟失。
我們需要調用fs.fsync方法對文件進行同步操作

var buf = new Buffer('我喜愛編程')
fs.open('./message.txt','a',function (err,fd) {
    fs.write(fd,buf,12,3,null,function (err,written,buffer) {
        if(err){
            console.log(err)
        }
        console.log('success')
        fs.fsync(fd)
        fs.close(fd)
    })
})

創建與讀取目錄

fs.mkdir(path,[mode],callback)創建目錄
mode參數值用於指定該目錄的權限,默認值0777

fs.mkdir('./test',function (err) {
    if(err){
        console.log(err)
    }else{
        console.log('success')
    }
})

fs.readdir(path,callback) 讀取目錄

fs.readdir('./',function (err,files) {
    if(err){
        console.log(err)
    }else{
        console.log(files)
    }
})

查看與修改文件或目錄的信息

在fs模塊中,可以使用stat方法或lstat方法查看一個文件或目錄的信息,區別是當查看符號鏈接文件時必須使用lstat()
fs.stat(path,callback)

fs.stat('./message.txt',function (err,stats) {
    console.log(stats)
})

stats對象擁有以下屬性和方法
技術分享圖片
技術分享圖片
技術分享圖片
在使用open方法打開文件並返回文件描述符後可以使用fs.fstat()查看文件信息
fs.fstat(fd,callback)

檢查文件是否存在

fs.access(path[, mode], callback)
mode 默認為 fs.constants.F_OK。

fs.access(file, (err) => {
  console.log(`${file} ${err ? '不存在' : '存在'}`);
});

獲取文件或目錄的絕對路徑

fs.realpath(path[, options], callback)

fs.realpath('./message.txt',function (err,resolvedPath) {
    if(err)throw err
    console.log(resolvedPath)
})

修改文件訪問時間及修改時間

fs.utimes(path, atime, mtime, callback)
atime參數用於指定修改後的訪問時間
mtime參數用於指定修改後的修改時間

let file = './message.txt';
fs.utimes(file,new Date(),new Date(),function (err) {
    if(err)console.log(err)
    console.log('success')
})

在open方法打開的文件並返回文件描述符後可以使用fs.futimes()修改文件的修改時間或訪問時間
fs.futimes(fd,atime,mtime,callback)

修改文件或目錄的讀寫權限

fs.chmod(path, mode, callback)

let file = './message.txt';
fs.chmod(file,0755,function (err) {
    if(err)console.log(err)
    else console.log('success')
})

移動文件或目錄

fs.rename(oldPath, newPath, callback)

fs.rename('舊文件.txt', '新文件.txt', (err) => {
  if (err) throw err;
  console.log('已完成重命名');
});

創建與刪除文件的硬鏈接

可以使用link方法創建文件的硬鏈接(表面上是兩份文件,其實是一份文件,修改一個會影響其他)
fs.link(srcpath,dstpath,callback)
srcpath用於指定需要被創建硬鏈接的文件的完整路徑及文件名
dstpath用於指定被創建的硬鏈接的完整路徑及文件名

let file = "./message.txt";
fs.link(file, "./test/test.txt", function(err) {
    if (err) console.log(err);
    else console.log("success");
});

刪除硬鏈接
fs.ulink(path,callback)

創建與查看符號鏈接

可以使用fs.symlink方法來創建文件或目錄的符號鏈接
fs.symlink(srcpath, dstpath,[type], callback)
srcpath用於指定需要被創建符號鏈接的文件的完整路徑及文件名
dstpath用於指定被創建的符號鏈接的完整路徑及文件名
type參數用於指定為文件創建符號鏈接還是目錄鏈接,默認file
file:文件創建符號鏈接,
dir目錄創建符號鏈接(junction:windows系統中的目錄創建符號鏈接)

fs.symlink('./a','./b','dir',function(err){
    if(err){
        console.log(err)
    }else{
        fs.symlink(__dirname+'/a/test.txt',__dirname+'/b/anotherMessage.txt','file',function (err) {
            if(err)console.log(err)
            else console.log('success')
        })
    }
})

readlink方法用於讀取符號鏈接中所包含的另一個文件或目錄的路徑及文件名操作
fs.readlink(path,callback)

截斷文件

fs.trunkcate(filename,len,callback)
len參數值為一個整數,用於指定需要被截斷後的文件尺寸

let file = './message.txt';
fs.truncate(file,9,function(err){
    if(err){
        console.log(err)
    }else{
        fs.stat(file,function(err,stats){
            console.log(stats.size)
        })

    }
})

刪除空目錄

fs.rmdir(path,callback)

監視文件或目錄

fs.watchFile(filename[, options], listener)
監視 filename 的變化。 每當文件被訪問時會調用 listener。
options 對象可以有一個布爾值的 persistent 屬性,表明當文件正在被監視時,進程是否繼續運行。
options 對象可以指定一個 interval 屬性,指定目標每隔多少毫秒被輪詢。 默認值為 { persistent: true, interval: 5007 }。
listener 有兩個參數,當前的狀態對象curr和以前的狀態對象prev:

let file = './message.txt';
fs.watchFile(file,function(curr,prev){
    if(Date.parse(prev.ctime)==0){
        console.log('文件被創建')
    }else if(Date.parse(curr.ctime)==0){
        console.log('文件被刪除')
    }else if(Date.parse(prev.mtime)!==Date.parse(curr.mtime)){
        console.log('文件被修改')
    }
})

可以用unwatchFile()取消當前文件發生變化時所要執行的處理
fs.unwatchFile(filename,[listener])
可以使用watch()方法對文件或目錄進行監視變化並執行某些處理
var watcher = fs.watch(filename,[options],[listener])
listener 有兩個參數 (eventType, filename)。 eventType 可能是 ‘rename‘ 或 ‘change‘,filename 是觸發事件的文件名。

let file = './message.txt';
var watcher= fs.watch(file,function(event,filename){
    console.log(event)
    console.log(filename)
    watcher.close()//停止監控
})

使用ReadStream對象讀取文件

fs.createReadStream(path,[options])
options參數為一個對象可使用的屬性如下
技術分享圖片

var file = fs.createReadStream('./message.txt',{start:3,end:12})
file.on('open',function(fd){//開始讀取數據
    console.log('start')
})
file.on('data',function(data){//讀取到數據
    console.log('read',data.toString())
})
file.on('end',function(){//讀取完畢
    console.log('end')
})
file.on("close", function() {//文件關閉
    console.log("close");
});
file.on("error", function() {//讀取失敗
    console.log("error");
});
file.pause()//暫停讀取
file.sume()//恢復讀取

使用writeStream對象寫入文件

fs.createWriteStream(path,[options])
options對象屬性
flags 詳見支持的 flag。默認為 ‘w‘。
encoding 默認為 ‘utf8‘。
fd 默認為 null。文件描述符。
mode 默認為 0o666。
autoClose 默認為 true。
start 開始寫入位置

對路徑進行操作

path.normalize(path)
技術分享圖片

var fs = require("fs");
var path = require("path");
var myPath = path.normalize(".//a//b//c/e");
console.log(myPath);// a/b/c/e

path.join([...paths])
使用平臺特定的分隔符把所有 path 片段連接到一起,並規範化生成的路徑

path.join('/foo', 'bar', 'baz/asdf', 'quux', '..'); // '/foo/bar/baz/asdf'

path.resolve([...paths])
將路徑或路徑片段處理成絕對路徑。

var path = require('path')
var myPath = path.resolve('a','b','c') 

path.dirname(p)
獲取路徑中的目錄名
當參數為目錄路徑時,該方法返回該目錄的上層目錄
當參數為文件路徑時,該方法返回該文件所在目錄
path.basename(p,[ext])
用於獲取一個路徑中的文件名

path.basename('./foo/bar/baz/index.html','.html')// index

extname()獲取一個路徑中的擴展名
path.extname(p)
path.sep屬性為操作系統的文件分隔符
path.delimiter屬性為操作系統指定的路徑分隔符

第10章 Node.js中的錯誤處理與斷言處理

在js中雖然可以使用try...catch機制來捕捉同步方法中拋出的錯誤,但是不能使用try...catch機制來捕捉異步方法中拋出的錯誤

創建並使用domain對象

var domain = domain.create()

當該對象捕捉到任何錯誤時,觸發該對象的error事件,

var domain=require('domain');
var fs=require('fs');
var d = domain.create();
d.name='d1';
d.on('error', function(err) {
    console.error('%s捕獲到錯誤!',d.name,err);
});
d.run(function() {
    process.nextTick(function() {
        setTimeout(function() { //模擬一個回調函數
            fs.open('non-existent file', 'r', function(err, fd) {
                if (err) throw err;
            });
        }, 1000);
    });
});

綁定回調函數與攔截回調函數

domain.bind(),將回調函數與domain對象進行綁定,從而捕捉回調函數的錯誤

var fs=require('fs');
var domain = require('domain');
var d = domain.create();
fs.readFile('./test.txt',d.bind(function(err, data) {
    if(err) throw err;
    else console.log(data);
}));
d.on('error', function(err) {
    console.log('讀取文件時發生以下錯誤:');
    console.log(err);
});

domain,intercept()方法攔截一個回調函數中的錯誤,該方法與bind的區別在於回調函數中必須使用throw關鍵字拋出錯誤

var fs=require('fs');
var domain = require('domain');
var d = domain.create();
fs.readFile('./test.txt',d.intercept(function(err, data) {
    console.log(data);
}));
d.on('error', function(err) {
    console.log('讀取文件時發生以下錯誤:');
    console.log(err);
});

《node.js權威指南》讀書筆記