阅读 217

流 steam一些基础知识

概念

  • 流是一组有序的,有起点和终点的字节数据传输手段
  • 它不关心文件的整体内容,只关注是否从文件中读到了数据,以及读到数据之后的处理
  • 流是一个抽象接口,被 Node 中的很多对象所实现。比如HTTP 服务器request和response,process.stdout 就都是流的实例。

Stream 有四种流类型,且所有的 Stream 对象都是 EventEmitter 的实例:

  • Readable – 可读流。
  • Writable – 可写流。
  • Duplex – 可读写的流.
  • Transform – 在读写过程中可以修改和变换数据的 Duplex 流

可读流

  • open - 打开文件 //不是每个流的处理都需要触发open事件,只有文件才需要,socket,http不需要
  • data – 开启流动模式。内部会监听是否添加data事件,添加后会立即读取不断读取文件
  • end – 没有更多的数据可读时触发。
  • close - 关闭文件
  • error – 在接收和写入过程中发生错误时触发。
  • finish – 所有数据已被写入到底层系统时触发。
  • readable -事件
let rs = fs.createReadStream(path,{})
//先把缓存区填满,等待被消费;
// 1、当缓存区被清空后,会再次触发readable事件
// 2、当缓存区长度小于highWaterMark时,会再次读取highWaterMark长度到缓存区
rs.on('readable',()=>{
    rs.read(n)  // 读取n个字节 不传参数表示读完,当n小于highWaterMark时,是同步从缓存中读取的。当n大于highWaterMark,会先改变highWaterMark的值再读取数据
    rs._readalbeState.length  // 缓存区的长度
})
复制代码

例如:

let rs = fs.createReadStream(path,{
    flags:'r',
    encoding:'utf8', //默认是null,表示buffer, 可写流默认utf8
    highWaterMark:3,  // 默认64k,可写流默认16k
    start:0,
    end:10, //包前包后
})
rs.setEncoding('utf8')

rs.on('open',()=>{})
rs.on('data',()=>{
    rs.pause() // 暂停
})
rs.on('end',()=>{})
rs.on('close',()=>{})
rs.on('error',()=>{})

setTimeout(()=>{
    re.resume() // 恢复data事件
},4000)

复制代码

可写流

  • drain —缓冲区已满并清空的时候触发
  • write -写入数据,第一次是真正的写入,后面的写入操作都是先存入缓存区,然后再第一次写入后再来清空缓存区
  • end

例如:

let ws = fs.createWriteStream(path,options)  
let flag = ws.write(string | buffer,'utf8',()=>{}) // flag 是否可写的标记,第一次是真正的往文件里面写入,后面的先存入缓存,然后在第一次写入后再清空缓存区并写入
复制代码
pipe方法的原理
//用法:
readStream.pipe(writeStream);
var from = fs.createReadStream('./1.txt');
var to = fs.createWriteStream('./2.txt');
from.pipe(to);

// 实现:
var fs = require('fs');
var ws = fs.createWriteStream('./2.txt');
var rs = fs.createReadStream('./1.txt');
rs.on('data', function (data) {
    var flag = ws.write(data);
    if(!flag)
    rs.pause();
});
ws.on('drain', function () {
    rs.resume();
});
rs.on('end', function () {
    ws.end();
});
复制代码

Duplex 流与 Transform 流

Duplex 流是同时实现了 Readable 和 Writable 接口的流。
Duplex 流的实例包括了:

  • TCP sockets
  • zlib streams
  • crypto streams

变换流(Transform streams) 是一种 Duplex 流。它的输出与输入是通过某种方式关联的。和所有 Duplex 流一样,变换流同时实现了 Readable 和 Writable 接口。

变换流的实例包括:

  • zlib streams
  • crypto streams

自定义可读流

用Readable创建对象readable后,便得到了一个可读流。 如果实现_read方法,就将流连接到一个底层数据源。 流通过调用_read向底层请求数据,底层再调用流的push方法将需要的数据传递过来。 当readable连接了数据源后,下游便可以调用readable.read(n)向流请求数据,同时监听readable的data事件来接收取到的数据。

let fs = require('fs');
let { Readable } = require('stream');
// createReadStream 调用的是ReadStream这个类,这个类是继承于Readable接口的
// ReadStream这个类实现了一个_read方法(这个方法实现了fs.read)

class MyRead extends Readable{
  _read(){ // 流需要实现一个_read方法
    this.push('100');
    this.push(null); // 如果push null后表示没有可以读到的内容了就
  }
}
let r = new MyRead();
r.on('data',function (data) {
  console.log(data);  // 100
});
r.on('readable',function (params) {  // data、readable方法不能同时调用,流消费完了就没有了
  let ret = r.read(1);
  console.log(ret);
})
复制代码

自定义可写流

let fs = require('fs');
let { Writable } = require('stream');

class MyWrite extends Writable{
  _write(chunk,encoding,clearBuffer){ // 可写流必须要调用回调函数,清空缓存
    console.log(chunk);
    clearBuffer();
  }
}
let myWrite = new MyWrite();
myWrite.write('1','utf8',()=>{
  console.log('成功')
});
myWrite.write('1', 'utf8', () => {
  console.log('成功')
});
复制代码
文章分类
阅读
文章标签