Fork me on GitHub

《node.js权威指南》读书笔记

第一章 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);
});
posted @ 2019-01-15 16:00  Jesse131  阅读(447)  评论(0编辑  收藏  举报