node.js中stream如何制作自己的流?

86 阅读2分钟

stream中的内容都比较抽象,所以详细记录一下,防止遗忘。

0.stream流的分类

  • writable:可写
  • readable:可读
  • duplex:可写可读(双向)
  • transform:可读可写(变化)

image.png

1.writable

①具体方法见:

stream 流 | Node.js API 文档 (nodejs.cn)

②实现原理:

image.png

③代码演示:

const {Writable} = require('stream')
const outStream = new Writable({
    write(chunk,encoding,callback){
        console.log(chunk.toString())
        callback()
    }
})
process.stdin.pipe(outStream)

④运行逻辑:

当node运行文件后,控制台输入什么,对应就会写入outStream中,于是控制台也对应输出同样的字符。

process.stdin.pipe(outStream)
//等价于
process.stdin.on('data',(chunk)=>{
    outStream.write(chunk)
})

2.1readable

我read的source中有多少我直接流给你多少

①具体方法见:

stream 流 | Node.js API 文档 (nodejs.cn)

②实现原理:

实现原理和writable差不多,只不过是换了一下API,还有pipe的输入输出。

③代码演示:

const {Readable} = require('stream')

const inStream = new Readable()

inStream.push('ABCDEFG')
inStream.push('HIJKLMN')
inStream.push('OPQRSTU')
inStream.push('VWXYZ')

inStream.push(null)

inStream.pipe(process.stdout)

④运行逻辑:

当node运行文件后,控制台会读取inStream中的内容,然后输出。

inStream.pipe(process.stdout)
//等价于
inStream.on('data',(chunk)=>{
    process.stdout.write(chunk)
})

2.2readable

你需要read多少,我流给你多少数据

①具体方法见:

stream 流 | Node.js API 文档 (nodejs.cn)

②实现原理:

实现原理和writable差不多,只不过是换了一下API,还有pipe的输入输出。

③代码演示:

const {Readable} = require('stream')

const inStream = new Readable({
    write(size){
        this.push(String.fromCharCode(this.currentCharCode++))
        if(this.currentCharCode>90){
            this.push(null)
        }
    }
})

inStream.currentCharCode = 65
inStream.pipe(process.stdout)

④运行逻辑:

当node运行文件后,控制台会读取inStream中的内容,然后输出。currentCharCode是一种编码,转换过来就是A-Z

3duplex

制作一个流,可以读也可以写,但是读写互不干扰

  • 这个把前面的做了后,就非常简单了。
const {Duplex} = require('stream')

const inOutStream = new Duplex({
    write(chunk,encoding,callback){
        encoding='utf-8'
        console.log(chunk.toString())
        callback()
    },
    read(size){
        this.push(String.fromCharCode(this.currentCharCode++))
        if(this.currentCharCode > 90){
            this.push(null)
        }
    }
})

inOutStream.currentCharCode = 65;
process.stdin.pipe(inOutStream).pipe(process.stdout)

4.0transform

①transform和duplex的差别

duplex的可读和可写是互不干扰的,而transform是相互影响的。

②transform示例

const {Transfrom} = require('stream')

const upperCaseTr = new Transform({
    transform(chunk,encoding,callback){
        this.push(chunk.toString().toUpperCase())
        callback()
    }
})

process.stdin.pipe(upperCaseTr).pipe(process.stout)

4.1transform内置流

代码示范1

const fs = require('fs')
const zlib = require('zlib')
const file = process.argv[2]

fs.createReadStream(file)
    .pipe(zlib.createGzip())
    .pipe(fs.createWriteStream(file+'.gz'))

代码示范2

添加进度条

const fs = require('fs')
const zlib = require('zlib')
const {Transform} = require('stream')
const file = process.argv[2]

const reportProgress = new Transform({
    transform(chunk,encoding,callback){
        process.stdout.write('.')
        callback(null,chunk)
    }
})

fs.createReadStream(file)
    .pipe(zlib.createGzip())
    .pipe(reportProgress)
    .pipe(fs.createWriteStream(file+'.zz'))
    .on('finish',()=>{
        console.log('Done')
    })

代码示范3

添加加密,然后解压缩

const crypto = require('crypto')
const fs = require('fs')
const zlib = require('zlib')

fs.createReadStream(file)
    .pipe(zlib.createGzip())
    .pipe(crypto.createCipher('aes192','123456'))
    .pipe(reportProgress)
    .pipe(fs.createWriteStream(file+'.zz'))
    .on('finish',()=>{console.log('Done')})