可读流模式
·内部有flowing(流动)模式和非flowing(暂停)模式来读取数据
·flowing模式使用操作系统的内部IO机制来读取数据,并尽可能快的提供数据
·非flowing模式时流默认处于暂停模式,必须显示调用read方法来读取数据
注意:如果没有绑定data事件处理器,并且没有pipe()目标,同时流被切换到流动模式,那么数据会丢失。比如没有绑定data事件,但是触发了resume方法。
·如何切换到流动模式
-添加一个data事件处理器来监听数据
-调用resume()方法来明确开启数据流
-调用pipe()方法将数据发送到一个Writable可写流
·切换回暂停模式
-如果没有导流目标,调用pause()方法。
-如果有导流目标,移除所有data事件处理器,调用unpipe()方法移除所有导流目标
可读流的事件
readable:监听readable会使数据从底层读到系统缓存区,读到数据后或者排空后如果再读到数据,会触发readable事件
data:绑定一个data事件监听器会将流切换到流动模式,数据会被尽可能的读出
end:该事件会在读完数据后被触发
error:当数据接收发生错误时触发
close:当底层数据源(比如:源头的文件描述符)被关闭时触发,并不是所有流都会触发这个事件
可读流的方法
read:在readable事件触发时的回调函数里读取数据
setEncoding:指定编码
pause:通知对象停止触发data事件
resume:通知对象恢复触发data事件
pipe:设置管道,将可读流里的内容导入到参数指定的可写流中
unpipe:取消数据通道
unshift:把数据块插回队列开头
写一个readStream.js:
var fs = require('fs');
var rs = fs.createReadStream('./read.txt',{start:0,end:5,encoding:'utf8'})//读取字节始末位置,包前也包后,所以此处读取的是6个字节
var buffers = [];
rs.on('readable',function(){//结合highWaterMark使用
var buff;
while(null != (buff = rs.read(1))){
buffers.push(buff);
}
})
rs.on('end',function(data){
var data = Buffer.concat(buffers)
console.log('读取完成',data.toString());
})
可写流模式
使用各种实现stream.Writable接口的对象来将流数据写入到对象中
fs.writeStream:写入文件
http.ClientRequest:客户端请求对象
http.ServerResponse:http中的响应对象,response.write()
net.socket:TCP中的socket对象
process.stdout:标准输出
process.stderr:错误输出
Gunzip:解压
可写流的方法
-write 写入数据 writable.write(chunk,[encoding],[callback]),其中chunk是写入的数据,为Buffer或者字符串。该方法的返回值为布尔值,系统缓存区定满时为false,未满时为true
-end 结束写入数据时触发,迫使缓存区中的数据立即写入目标对象,调用后不能再写入
var fs = require('fs');
var rs = fs.createReadStream('./read.txt',{start:0,end:5,encoding:'utf8'})//读取字节始末位置,包前也包后,所以此处读取的是6个字节
var ws = fs.createWriteStream('./write.txt')
ws.on('open',function(){
console.log('写入文件已打开');
})
rs.on('data',function(data){
ws.write(data)
})
rs.on('end',function(){
ws.end('写入完成,关闭可写流',function(){
console.log('写入完毕,共写入%d字节',ws.bytesWritten);
})
})
大文件读取流程
1,从文件读入缓存区并填满
2,把缓存区的数据写入目标文件,同时读取剩余数据到内存中,write返回false
3,缓存区中的数据全部写入后触发drain事件
4,先将内存中的数据写入缓存区,再读取文件剩余数据到缓存区直到填满(只能从缓存区向目标文件写数据)
5,持续上述步骤,直到完成
模拟大文件读取流程bigfile.js:
var fs = require('fs');
var rs = fs.createReadStream('./big.fbr')//默认是64k,所以尽量选择一个大文件来模拟
var ws = fs.createWriteStream('./big2.fbr')//默认是16k
ws.on('open',function(){
console.log('写入文件已打开');
})
rs.on('data',function(data){
var flag = ws.write(data)
console.log(flag);
})
ws.once('drain',function(){//可写流的缓存区的数据全部写到目标文件时触发
console.log(drain);
})
pipe:将数据的滞留量限制到一个可接受的水平,以使得不同速度的来源和目标不会淹没可用内存
readStream.pipe(writeStream,[options])
var fs = require('fs');
var rs = fs.createReadStream('./big.fbr')//默认是64k,所以尽量选择一个大文件来模拟
var ws = fs.createWriteStream('./big2.fbr')//默认是16k
rs.pipe(ws)
pipe方法的原理为:
rs.on('data',function(data){
var flag = ws.write(data)
if(!flag){
rs.pause();
}
})
ws.on('drain',function(){
rs.resume();
})