可读流与可写流

可读流模式

·内部有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();
})
原文地址:https://www.cnblogs.com/web-fengmin/p/6398833.html