nodeJS
来源:互联网 发布:安卓大尺度直播软件 编辑:程序博客网 时间:2024/06/05 17:09
Stream 数据流
说明
Node.js 中的许多组件提供连续输入或可连续处理输入的功能,为了让这些组件行为一致,strean API 提供了一个抽象的接口,提供了常用的方法,以及数据流具体实现时需要使用的属性。数据流分为可读、可写、可读写,所有的流都是 Event Emitter 的实例,都可以主动触发事件。
参考
- Node.js 文档
- JavaScript 标准参考教程 Node.js
Node.js 中有以下两种缓存处理方式:
- 第一种是传统的读取文件方式,等到所有数据接收完毕,一次性从缓存中读取,然后处理,优点是简单直接自然,缺点是遇到大文件,需要换很长事件加载。才能进入数据处理步骤
- 第二种是 ‘数据流’ 的方式,每次只读取一小块数据,向了流水一样,每读取一小块数据,就触发一个事件,在这个事件中可以进行数据的处理,即在数据没有完全接受完成时,就开始处理它,可以提高程序的性能。
数据流是不同进程之间传递数据的一种方式。管道命令
pipe
就起到在不同命令之间连接数据流的作用。‘数据流’ 相当于把较大的数据拆分成为很小的部分,一个命令只要部署了数据流接口,就可以把一个流的输出接到另一个流的输入。数据流通过事件通信,具有readable、writable、drain、data、end、close
等事件,既可以读取数据,也可以写入数据,每读取或者写入一段数据,就会触发一次 data 事件。对象模式:使用 Node.js API 创建的流对象只能操作 strings 或者 buffer ,但是,通过一些第三方流的实现,你依然能够处理其他类型的 JavaScript 值(除了 null),这些流被认为是工作在‘对象模式’,在创建流的实例时,可以通过
objectMode
选项使流的实例切换到对象模式。
1. 可读数据流
‘可读数据流’ 用来产生数据。它表示数据的来源,只要一个对象提供 ‘可读数据流’, 就表示你可以从其中读取数据
const Readable = require('stream').Readable; const rb = new Readable(); rb.push('ttt'); // readable.push() 将数据添加到读取队列 rb.push(' kskskss'); rb.push(null); // 提示 readable 数据输入完成 /* .pipe() 用于连接数据流 process.stdout 标准输出 */ rb.pipe(process.stdout);
1. 可读流存在两种模式和三种状态
两种模式
flowing
流动模式,可读流自动从系统底层读取数据,并通过事件发射器接口尽快将数据提供给应用paused
暂停模式,必须显示的调用stream.read()
可读流才会释放数据,新建的时候可读流处于暂停态
三种状态,可读流装台可以通过
readable._readableState.flowing
获得
null
不存在数据消费者,可读流将不会产生数据true
数据流处在 流动模式,生成数据false
数据流处于 暂停模式,会暂停事件流,但是不会暂停数据生成,数据会堆积到流的内部缓存中
paused
暂停模式 转变为flowing
流动模式的方法:
- 添加
data
事件的监听函数 - 调用
stream.resume()
方法 - 调用
stream.pipe()
方法将数据发送到下一个可写数据流
转化为流动模式时,如果没有
data
事件监听函数,也没有pipe
方法的目的地,数据将会遗失
flowing
流动模式 转变为paused
暂停模式 的方法:
- 如果不存在管道目标,通过调用
stream.pause()
实现 - 如果存在管道目标,1)取消
data
监听事件;2)调用stream.unpipe()
方法移除管道目标
const fs = require('fs'); const readableStream = fs.createReadStream('./test.txt'); let data = ''; let count = 0; // 初始状态,未产生数据 console.log(readableStream._readableState.flowing); // null // 开始监听 ‘data’事件, 可读流切换到 flowing 流动模式 readableStream.on('data', function (chunk) { data += chunk; count ++; console.log(readableStream._readableState.flowing); // true 流动模式下状态为 true if (count === 4) { // 通过 pause 方法,暂停可读流,切换到 paused 暂停模式 readableStream.pause(); console.log('pause', readableStream._readableState.flowing); // pause false 暂停模式下状态为 false setTimeout(function () { // 通过 resume 方法 继续释放 data 事件,切换到 flowing 流动模式 readableStream.resume(); console.log('resume', readableStream._readableState.flowing); // resume true }, 1000) } })
2. 可读流中的事件
close
在流或者底层资源关闭后触发,然后不会再有任何事件被触发,不是所有的 可读流都会触发此事件data
回调函数中有参数chunk
表示数据片段,事件会在流将数据传递给消费者时触发,当流转换为flowing
模式时触发end
在流中再没有数据可供消费时触发error
在底层系统内部出错从而不能产生数据或者流的实现视图传递错误数据时触发readable
在流中有数据可供读取时触发,当到达流的尾部时,也会触发此事件
const fs = require('fs'); const readableStream = fs.createReadStream('./test.txt'); let data = ''; let count = 0; readableStream.on('data', function (chunk) { data += chunk; count++; if (count === 4) { readableStream.push({name: 'test'}); // 一个错误的操作,可以触发 error 事件 } }) /* readable 事件监听系统中有可读的数据,表明了流有了新的动态,要么有新的数据、要么到达尾部 可以使用 readableStream.read() 方法返回可用的数据,如果到达尾部则返回 null */ readableStream.on('readable', function () { // 不要与 'data' 事件一起用 while ((chunk = readableStream.read()) !== null) { data2 += chunk; } }) readableStream.on('error', function (err) { console.log('error', err); }) readableStream.on('end', function () { console.log('data', data); console.log(count); }) readableStream.on('close', function () { console.log('close'); })
3. 可读流中的属性和方法
readable
属性,表示当前数据流是否是一个可打开的数据流read([size])
方法,从内部不缓存区抽出并返回一些数据,如果没有可读的数据返回 null ,size
表示字节数setEncoding(encoding)
为从可读流读入的数据设置字符编码,可以使得数据流返回指定编码的字符串而不是 Bufferpause()
使得flowing
模式的流停止触发 ‘data’ 事件,切换为paused
模式resume()
使得 可读数据流 继续释放 data 事件,由flowing
模式 切换为paused
模式isPaused()
表示是否中断了可读数据流pipe(writableStream,[,options])
从可读数据流中读取数据写入可写数据流,是一个自动传送数据的机制,必须在可读数据流上调用,参数为可写数据流,可以采用链式语法,默认可读流end
时,可写流也会触发stream.end()
结束写入,禁用默认行为需要设置第二个参数{end: false}
unpipe([destination])
用于将之前通过pipe()
方法绑定的流分离,参数是可选填的,表示要分离的流
// 伪代码,有些接口不能一起使用 const fs = require('fs'); const readableStream = fs.createReadStream('./test.txt'); // 可读流 const writableStream = fs.createWriteStream('./output.txt'); // 可写流 let data = ''; let count = 0; // setEncoding 设置字符编码 readableStream.setEncoding('utf-8'); // pipe 自动读取写入 readableStream.pipe(writableStream); setTimeout(function () { console.log('开始分离流'); // unpipe 分离流 readableStream.unpipe(writableStream); console.log('结束分离流'); }, 10) console.log('1', readableStream.readable); // true 当前为可打开数据流 readableStream.on('data', function (chunk) { data += chunk; count++; console.log('2', readableStream.readable); // true 当前为可打开数据流 if (count === 4) { // pause 方法,暂停可读流,切换到 paused 暂停模式 readableStream.pause(); // isPaused 判断是否为 paused 暂停模式 console.log(readableStream.isPaused()) // true setTimeout(function () { // resume 方法 继续释放 data 事件,切换到 flowing 流动模式 readableStream.resume(); console.log(readableStream.isPaused()); // false }, 1000) } }) readableStream.on('readable', function () { let chunk; // read 从内部不缓存区抽出并返回一些数据 while (null !== (chunk = readableStream.read())) { console.log(chunk); } }) readableStream.on('end', function () { // console.log('data', data); console.log(count); console.log('3', readableStream.readable); // false 当前为不可打开数据流 })
2. 可写数据流
与可读数据流对应,可写数据流 用来接收数据,它允许将某个数据写入目的地,他是数据写入的一种抽象,素有 可写数据流 都实现了
stream.Writable
类定义的接口
1. 可写流的属性和方法
writable
属性,如果流仍然打开,并且可写,就返回true
否则返回false
write(chunk[, encoding][, callback])
方法,用于向可写数据流写入数据,1)第一个参数表示写入的内容,可以是字符串可以是一个 stream 对象或 buffer 对象,对象模式下可以是任意 javascript 值,2)第二个参数可选,表示编码规范,3)第三个参数是缓冲数据输出时的回调函数;4)write()
方法具有返回值,如果要等待drain
事件触发才能继续写入数据,将返回false
,否则返回true
cork()
方法,强制将所有写入数据都存放到内存中的缓冲区里,知道调用stream.uncork()
或stream.end()
方法时,缓冲区里的数据才会被输出,可以用来避免向流中写入大量小数据块导致的性能下降问题uncork
输出在cork()
方法调用后缓存在内存中的数据setDefaultEncoding(encoding)
方法,设置默认编码end([chunk][,encoding][,callback])
方法, 结束写入数据,1)第一个参数,最后写入的数据;2)第二个参数,编码规范;3)流结束的回调函数。在调用了stream.end()
方法之后,再调用stream.write()
方法将会导致错误destroy()
摧毁这个流
// 伪代码,有些接口不能一起使用 const fs = require('fs'); const readableStream = fs.createReadStream('./test.txt'); // 可读流 const writableStream = fs.createWriteStream('./output.txt'); // 可写流 let data = ''; let count = 0; // 设置编码 writableStream.setDefaultEncoding('utf-8'); // cork 强制将所有写入数据都存放到内存中的缓冲区 writableStream.cork(); readableStream.on('data', function (chunk) { // write 向可写数据流写入数据 const ret = writableStream.write(chunk, 'utf-8', function () { console.log('finish'); }); count++; // console.log(ret); // writable 是否流仍然打开,并且可写 console.log(writableStream.writable); // true }) readableStream.on('end', function () { console.log(count); console.log(writableStream.writable); // true // destroy 摧毁这个流 writableStream.destroy(); // uncork 释放缓存在内存中的数据 writableStream.uncork(); // end 结束写入数据 writableStream.end('\n结束了!'); console.log(writableStream.writable); // false end() 之后不可写入 })
2. 可写流中的事件
drain
(耗尽)事件,writable.write(chunk)
返回false
以后,当缓存数据全部写入完成,可以继续写入时,会触发drain事件,表示缓存空了。finish
与end()
方法最后参数回调函数用法一致,都是 end 之后,缓存数据释放,触发finish
事件pipe
事件, 绑定在可写流上,在可读流触发pipe
方法,将数据流导入此可写流上时触发事件,回调函数接受 可读流对象为参数unpipe
事件,可读流调用unpipe()
方法将可写数据流移出写入的目的地时触发此事件,该事件的回调函数,接受发出该事件的“可读数据流”对象作为参数error
事件,如果写入数据或pipe数据时发生错误,就会触发该事件。close
事件,事件将在流或其底层资源(比如一个文件)关闭后触发
// 伪代码,有些接口不能一起使用 const fs = require('fs'); const readableStream = fs.createReadStream('./test.txt'); // 可读流 const writableStream = fs.createWriteStream('./output.txt'); // 可写流 let data = ''; let count = 0; // drain 缓存空了事件 writableStream.on('drain', function () { console.log('drain'); }) // finish 结束 writableStream.on('finish', function () { console.log('finish'); }) // pipe 管道流导入 writableStream.on('pipe', function (src) { console.log('soming piping'); }) // unpipe 管道流中断 writableStream.on('unpipe', function (src) { console.log('soming unpiping'); }) // error 报错 writableStream.on('error', function (err) { console.log('error', err); }) // close 最后关闭 writableStream.on('close', function () { console.log('close'); }) // 通过管道导入流 readableStream.pipe(writableStream); setTimeout(function () { // 分离流,导入停止 readableStream.unpipe(writableStream); }, 5) readableStream.on('data', function (chunk) { const ret = writableStream.write(chunk); count++; console.log('ret', ret); }) readableStream.on('end', function () { console.log(count); writableStream.end('\n结束了!'); })
3. Duplex 流(可读、可写)
Duplex 流是同时实现了 Readable 和 Writable 接口的流。
4. Transform (变换)流
也是一种 Duplex 流,他的输入与输出时通过某种方式关联的
- nodejs
- NodeJs
- nodejs
- nodejs
- nodejs
- nodejs
- nodejs
- nodejs
- nodejs
- nodejs
- NodeJs
- nodejs
- NodeJS
- nodejs
- nodejs
- nodejs
- NodeJS
- nodejs
- Laravel Call to a member function setCookie() on null
- 关于正则化的理解
- C语言的操作符
- scikit-learn 中文文档-特征选择-监督学习|ApacheCN
- leetcode 155. Min Stack
- nodeJS
- exKMP 学习小记
- TextView中动态显示某些值
- 最新十大web安全隐患-四年之后,OWASP发布新版本OWASP Top10 2017
- ubuntu 16.04下编译GLFW
- JAVA11.6作业
- nodeJS
- java.sql.SQLException: Value '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp
- 深度优先搜索(dfs)