概念

流(stream)是 Node.js 中处理流式数据的抽象接口。 stream 模块用于构建实现了流接口的对象。

Node.js 提供了多种流对象。 例如,HTTP 服务器的请求和 process.stdout 都是流的实例。

流可以是可读的、可写的、或者可读可写的。 所有的流都是 EventEmitter 的实例。

访问 stream 模块:

const stream = require('stream');

尽管理解流的工作方式很重要,但是 stream 模块主要用于开发者创建新类型的流实例。 对于以消费流对象为主的开发者,极少需要直接使用 stream 模块。

Node.js 中有四种基本的流类型:

  • Writable - 可写入数据的流(例如 fs.createWriteStream())。
  • Readable - 可读取数据的流(例如 fs.createReadStream())。
  • Duplex - 可读又可写的流(例如 net.Socket)。
  • Transform - 在读写过程中可以修改或转换数据的 Duplex 流(例如 zlib.createDeflate())。

此外,该模块还包括实用函数 stream.pipeline()、stream.finished() 和 stream.Readable.from()。

盗图

如何获取内存中的流

可写流和可读流都会在内部的缓冲器中存储数据,可以分别使用的 writable.writableBuffer 或 readable.readableBuffer 来获取。

细节

可读流

两种模式

  • 流动模式(不用打,自己动):数据自动从底层系统读取,并通过EventEmitter接口的事件尽可能快的提供刚给应用程序
  • 暂停模式(打一下,动一下):必须显示调用stream.read()读取数据块

其实,所有可读流初始的时候都处于暂停模式,不过可以通过以下方法切换到流动模式

  • 添加 data 事件句柄。
  • 调用 stream.resume() 方法。
  • 调用 stream.pipe() 方法将数据发送到可写流。

当然,能切到暂停模式,肯定也能切到流动模式

  • 如果没有管道目标,则调用 stream.pause()
  • 如果有管道目标,则移除所有的管道目标。调用stream.unpipe()可以移除多个管道目标。

为了向后兼容,移除 'data' 事件句柄不会自动地暂停流。

如果有管道目标,一旦目标变为 drain 状态并请求接收数据时,则调用 stream.pause() 也不能保证流会保持暂停模式。

如果可读流切换到流动模式,且没有可用的消费者来处理数据,则数据将会丢失。 例如,当调用 readable.resume() 时,没有监听 'data' 事件或 'data' 事件句柄已移除。

添加 readable 事件句柄会使流自动停止流动,并通过 readable.read() 消费数据。 如果 readable 事件句柄被移除,且存在 data 事件句柄,则流会再次开始流动

demo

流动模式

const fs = require('fs')
const path = require('path')
const rs = fs.createReadStream(path.join(__dirname, './1.txt')) rs.setEncoding('utf8') rs.on('data', (data) => {
console.log(data)
})

暂停模式

const fs = require('fs')
const path = require('path')
const rs = fs.createReadStream(path.join(__dirname, './1.txt')) rs.setEncoding('utf8') rs.on('readable', () => {
let d = rs.read(1) // 要读取的数据的字节数。
console.log(d)
})

read方法: 参数 可选 [size]

如果没有指定 size 参数,则返回内部缓冲中的所有数据。

使用 readable.read() 处理数据时, while 循环是必需的。

read方法消耗的是内存中的数据

当read方法返回的是null的时候,会触发 流监听的 end 事件

不使用read消耗内存中的流数据,则不会触发end

预览一波

遇到的问题

process.stdin.setEncoding('utf8');

process.stdin.on('readable', () => {
let chunk;
while ((chunk = process.stdin.read()) !== null) {
process.stdout.write(`数据: ${chunk}长度${chunk.length}\n`);
}
}); process.stdin.on('end', () => {
process.stdout.write('结束\n');
process.exit(1);
});

上面的代码作用是读取用户在terminal上的输出,然后输出内容和长度,但是执行的时候,总是无法执行到end,不仅如此,就算内容为空,返回的长度也不为0,这让我很疑惑。

最后发现是坚挺的end事件,只有当read方法返回为null的时候才会触发,所以没有触发,而问题就在于返回的内容是换行符,不同系统下换行符不一样,mac下是\n,所以我们需要处理一下read返回的内容,然后手动end

查看字符串中回车符可以使用:

console.log(JSON.stringify(chunk));

修正后的代码为:

process.stdin.setEncoding('utf8');

process.stdin.on('readable', () => {
let chunk;
while ((chunk = process.stdin.read()) !== null) {
chunk = chunk.replace(/\n/g, '');
if (!chunk.length) {
console.log('输入为空');
return process.stdin.emit('end');
}
process.stdout.write(`数据: ${chunk}长度${chunk.length}\n`);
}
}); process.stdin.on('end', () => {
process.stdout.write('结束\n');
process.exit(1);
});

执行结果:

中文文档

node - 流 浅析的更多相关文章

  1. gulp基于node流的自动化构建工具

    GULP 在我才接触gulp的时候 看他就是一个 通过压缩各种文件来提升用户体验的开发工具   那是因为  对他的理解并不深    他真正强大 之处 在于他的     管子  .pipe()  可以 ...

  2. java中io流浅析

    1.java.io包下File类:java程序中的此类的一个对象,就对应着硬盘中的一个文件或网络中的一个资源.File file1 = new File("d:\\io\\helloworl ...

  3. Node流操作(启动器forever)

    详情: https://www.cnblogs.com/lalalagq/p/9749680.html 流:读取流,写入流,双向读写流. 读写流——压缩.加密 数据库不能直接接受流 sf.readFi ...

  4. Node.js 流

    稳定性: 2 - 不稳定 流是一个抽象接口,在 Node 里被不同的对象实现.例如request to an HTTPserver 是流,stdout 是流.流是可读,可写,或者可读写.所有的流是 E ...

  5. Node.js Streams:你需要知道的一切

    Node.js Streams:你需要知道的一切 图像来源 Node.js流以难以使用而闻名,甚至更难理解.好吧,我有个好消息 - 不再是这样了. 多年来,开发人员在那里创建了许多软件包,其唯一目的是 ...

  6. Node.js 全栈开发(一)——Web 开发技术演化

    这些年一直不断接触学习 Node 技术栈,个人的技术开发学习兴趣也越来越倾向 node 流.也许是由于英语的关系,也许是因为墙增加了学习国外一手资料的难度,加上现在流行的 web 开发技术并不太容易上 ...

  7. DB2 Catalog浅析&学习笔记

    原文地址:http://king123654789.iteye.com/blog/1296492 Catalog 是远程连接部署在服务器端的DB2数据库的命令 [本文涉及到的命令] >db2 c ...

  8. node.学习笔记(关于http2的讲解)

    个人总结:读完这篇文章需要30分钟 http2部分很有学习价值,可以好好看.  用node搭建TCP服务器 用node搭建HTTP服务器 用node文件fs模块对文件读取,并用流的方式写入 用url路 ...

  9. JavaScript资源大全中文版(Awesome最新版--转载自张果老师博客)

    JavaScript资源大全中文版(Awesome最新版)   目录 前端MVC 框架和库 包管理器 加载器 打包工具 测试框架 框架 断言 覆盖率 运行器 QA 工具 基于 Node 的 CMS 框 ...

随机推荐

  1. JAVA Rest High Level Client如何取聚合后得数据

    对于刚刚学习es的童鞋来说,很容易不清楚怎么获取客户端对es文档的聚合结果,下面就演示一下模仿DSL写聚合,然后获取到聚合对结果. 一, 对于下面这个简单的聚合,目的是对于文档全文匹配,聚合颜色字段. ...

  2. go中的数据结构切片-slice

    1.部分基本类型 go中的类型与c的相似,常用类型有一个特例:byte类型,即字节类型,长度为,默认值是0: bytes = []btye{'h', 'e', 'l', 'l', 'o'} 变量byt ...

  3. 创建windows系统下的虚拟机

    创建新的虚拟机  添加映像(windows系统下必须先添加映像) 选择相应的镜像文件:网上查找密钥输入:版本按要求选择:单击 下一步:设置虚拟机名称  位置 :下一步 默认的磁盘大小(不用管)——下一 ...

  4. hdu 1385 Minimum Transport Cost (Floyd)

    Minimum Transport CostTime Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Ot ...

  5. Linux菜鸟——常见命令一 权限

    Linux对文件和目录的权限位 权限位是十位 第一位 代表文件类型 - 普通文件 d 目录文件 l 链接文件 后面九尾 所有者权限 u = user 所属组权限 g = group 其他人权限 o = ...

  6. 白话布隆过滤器BloomFilter

    通过本文将了解到以下内容: 查找问题的一般思路 布隆过滤器的基本原理 布隆过滤器的典型应用 布隆过滤器的工程实现 场景说明: 本文阐述的场景均为普通单机服务器.并非分布式大数据平台,因为在大数据平台下 ...

  7. 对js中局部变量、全局变量和闭包的理解

    对js中局部变量.全局变量和闭包的理解 局部变量 对于局部变量,js给出的定义是这样的:在 JavaScript函数内部声明的变量(使用 var)是局部变量,所以只能在函数内部访问它.(该变量的作用域 ...

  8. Java基础知识总结之1.8新特性lambda表达式

    函数式接口 函数式接口(functional interface 也叫功能性接口,其实是同一个东西).简单来说,函数式接口是只包含一个方法的接口.比如Java标准库中的java.lang.Runnab ...

  9. 扛把子组2018092609-2 选题 Scrum立会报告+燃尽图 06

    此作业的要求参见[https://edu.cnblogs.com/campus/nenu/2019fall/homework/8681] 一.小组情况组长:迟俊文组员:宋晓丽 梁梦瑶 韩昊 刘信鹏队名 ...

  10. python3 之 文件read方法(read、readline、readlines)

    目录 一.read方法 二.readline方法 三.readlines方法 正文 python3中,读取文件有三种方法:read().readline().readlines(). 此三种方法,均支 ...