流是Node.js中一个非常重要的概念, 也是Node.js之所以适用于I/O密集型场景的重要原因之一。 流是Node.js移动数据的方式,流可以是可读的和/或可写的。在Node.js中很多模块都使用到了流, 包括HTTP和fs模块,本文将用尽可能简单的方式为你介绍Node中流的概念。

流 Stream

事实上,流通常用于将程序连接在一起。流可以被读和写。被流连接在一起的程序通常很小,并且只专注于做一件事。

你可能经常在项目中使用Gulp来做项目的代码构建,那么在使用过程中,你很可能碰到过类似下面的错误。 错误大概是这样个的:

stream.js:94throw er; // Unhandled stream error in pipe.

当初次碰到这种错误的时候,你可能和我一样对流的概念毫无头绪,好在我们可以借助Google来寻找答案。 一个最佳的开始是用Google搜索“node stream”之类的关键字, 从而我们可以获得stream-adventure这类的课程学习。

在Node.js的文档中,流(Stream)的官方定义如下:

流是一个抽象接口,在Node.js中它借助于多种对象实现。例如,一个对HTTP服务器的请求是一个流, 可以是stdout。流是可读的,可写的,或两者兼备。所有的流都是EventEmitter的实例。

也就是说,Node.js中的很多模块都是用到了流,例如httpfs模块。例如在文件系统模块(fs)中, 我们可以通过流来读写文件数据的实例。由于数据是流,这就意味着在完成文件读取之前, 从收到最初几个字节开始,就可以对数据动作。这是Node.js中的一个常见模式:

可读流

const fs = require('fs');
const stream = fs.ReadStream('name.txt');
stream.setEncoding('utf-8');
stream.on('data', chunk => {console.log('read some data');
});
stream.on('close', () => {console.log('all the data is read');
});

在上面的例子中,我们创建了一个可读流,并在流读取文件的过程中监听事件,在收到新数据时触发事件数据。 当文件读取完成后触发关闭事件。

此外,在流中,我们要负责按自己想要的方式使用数据,所以我们必须在数据事件接收到数据的时候处理它。 如果想要读区所有数据,就必须将其拼接到一个变量中:

let data = '';stream.on('data', chunk => {data += chunk;console.log('read some data');
});

如果读取的文件很大,这就会触发多个data事件,这就需要开发者可以在以接收到数据的时候就做一些事情, 而不是等到整个文件都读取完成。

可写流

显然,我们也可以创建可写流以便写数据。这意味着,只要一段简单的脚本,就可以使用流读入文件然后写入另一文件:

const fs = require('fs');
let readStream = fs.ReadStream('name.txt');
let writeStream = fs.WriteStream('out.txt');
readStream.setEncoding('utf-8');
readStream.on('data', chunk => {writeStream.write(chunk);
});
readStream.on('close', () => {writeStream.end();
});

在上面的例子中,当接收到data事件的时候,我们便将数据写入到可写流writeStream中,这非常的高效, 因为只要从可读文件接收到数据事件,数据就会被写入文件。尤其是对大文件而言,不会被阻塞。因此, 对于网络和文件系统中移动数据而言,流的方式非常的高效。

通过管道连接流

本质上,流允许你讲其他对象或程序连接在一起。你将某些输入,然后让它经过流, 将它传递到另一个程序中。我比较喜欢拿水管来做类比。将一组小型的管道(程序)连接在一起, 用于完成一些特定的任务。

管道(pipe)的概念很早就存在于Unix系统中,你可以通过这篇文章了解更多:Unix Pipelines

由于在输入和输出之间通过管道传输数据在Node.js中很常见,所以它也提供了连接两个可读和可写流并在它们之间通过管道传输数据的方法。 例如:readStream.pipe(writeStream)

pipe()方法会仔细处理事件,在需要的时候会暂停流并恢复流操作,所以除非需要对事件的发生有完全的控制权, 否则应该使用pipe()

const fs = require('fs');// 指定读取流,指向目标文件,编码格式为utf-8
const file = fs.createReadStream('hello.txt', {encoding: 'utf-8'});// 流是EventEmitter的实例,我们可以为其添加事件
// 当打开文件时触发open事件
file.on('open', function () {// 使用管道,将文件内容输出到屏幕上// process对象也是一个EventEmitter实例this.pipe(process.stdout);
});

References

  1. Introduction to streams
  2. Hack Reactor’s Video About Node Streams
  3. Stream (Node.js)
  4. File System (Node.js)
  5. Node Streams Article by Max Ogden

原文:http://wwsun.github.io/posts/stream-in-nodejs.html

转自:Node.js: 认识流stream

Node.js: 认识流stream相关推荐

  1. java文件边读边写_[Java教程]node.js 利用流实现读写同步,边读边写

    [Java教程]node.js 利用流实现读写同步,边读边写 0 2017-09-10 13:00:14 //10个数 10个字节,每次读4b,写1blet fs=require("fs&q ...

  2. (13)Node.js 文件流 缓冲 VS 流

    一.文件操作 – 缓冲方式 通过把源文件放入内存缓冲中,最后到目标文件.  首先先放入内存缓冲中  当内存缓冲满为止,才向目标文件进行传输  二.文件操作 - 流方式 将A作为读取流,然后传输到B写入 ...

  3. Node.js 文件系统流pipe到Http响应流中

    // 内置http模块,提供了http服务器和客户端功能(path模块也是内置模块,而mime是附加模块) var http=require("http"); var fs=req ...

  4. 在node.js响应流中,res.setHeader内设置多个Set-Cookie

    有时你可能想在response响应中设置两次相同的header属性,比如设置两个cookie(Set-Cookie),但writeHead或setHead出现两个相同的属性时会被覆盖并合并成一个 错误 ...

  5. Node.js stream模块(一)可读流

    目录 fs.readFile的问题 如何设计出内存友好的,且人性化的数据生产与消费模式 stream模块 创建可读流对象 _read的作用 push的作用 可读流对象的缓冲区buffer 水位线hig ...

  6. node.js Stream(流) 和 EJS 模板引擎——0822

    一.node.js 中的 Stream(流) 1.什么是 Stream ? Stream 是一个抽象接口,Node 中有很多对象实现了这个接口.例如,对http服务器发起请求的request 对象就是 ...

  7. 在 Node.js 中用子进程操作标准输入/输出

    翻译:疯狂的技术宅 原文:http://2ality.com/2018/05/chi... 本文首发微信公众号:jingchengyideng 欢迎关注,每天都给你推送新鲜的前端技术文章 在本中,我们 ...

  8. node JS獲取GPS_Node.js 14 正式发布:V8 引擎升级,新增异步本地存储 API

    Node.js 14 版本于近日正式发布, 此版本包含的亮点如下: 对诊断功能的改进 升级 v8 引擎 新增实验性的异步本地存储 API 强化流 API 移除实验性模块中的警告 移除一部分早期版本中废 ...

  9. base64 转二进制_一篇文章弄明白Node.js与二进制数据流

    1 认识二进制数据 二进制是计算技术中广泛采用的一种数制.二进制数据是用0和1两个数码来表示的数.它的基数为2,进位规则是"逢二进一",借位规则是"借一当二", ...

最新文章

  1. qq发文件大小上限_微信又放大招!网友:QQ可以卸载了?
  2. shell脚本编程之函数
  3. VirtualProtect VirtualLock VirtualUnlock
  4. 学习《Flask Web开发:基于Python的Web应用开发实战》分享
  5. 计算机进入安全模式,电脑怎么进入安全模式
  6. boost::geometry::detail::overlay::approximately_equals用法的测试程序
  7. ML.NET 示例:对象检测-ASP.NET Core Web和WPF桌面示例
  8. word2003插入页码
  9. IOS 中description 和 debugDescription的区别
  10. tomcat 7下spring 4.x mvc集成websocket以及sockjs完全参考指南(含nginx/https支持)
  11. 医疗信息化建设售后服务方案
  12. 获取文件夹下所有tif图片,并将16位图转为8位图
  13. utc时间 单位换算_国际时间换算
  14. HTML与Java组合使用_【自学java笔记#第五十四天#】javaweb day02 html和css的组合使用...
  15. java汉字转换为拼音
  16. 禁用计算机硬盘,禁止电脑每次开机都要自动扫描磁盘的多种方法
  17. C语言 模拟扑克牌新牌洗牌与发牌
  18. 香侬科技独家对话Facebook人工智能研究院首席科学家Devi Parikh
  19. 什么是构造函数,什么是析构函数,作用是什么?
  20. 第二次阅读作业--12061161 赵梓皓

热门文章

  1. Mindis(HDU-6670)
  2. 暑期训练日志----2018.8.3
  3. Charm Bracelet(POJ-3624)
  4. 理论基础 —— 查找 —— 顺序查找
  5. 大整数的因子(信息学奥赛一本通-T1171)
  6. 25 FI配置-财务会计-定义冲销原因
  7. 10.1 SQ03维护用户组
  8. 计算机报名锁定后可以修改吗,网上报名正式提交后 报名信息即被锁定 无法修改...
  9. 掌握spec只需读这一篇文章,CentOS、RedHat、SUSE粉的福利来了
  10. POCO C++ Libraies介绍及常见用法