Stream是Node.js中的抽象接口,有不少Node.js对象实现自Stream。

所有的Stream对象都是EventEmitter 的实例。

例如:fs模块(用于读写操作文件的模块)

fs的FSWatcher接口继承自events.EventEmitter,以下是fs模块的部分源码:

 interface FSWatcher extends events.EventEmitter {
close(): void;
/**
* events.EventEmitter
* 1. change
* 2. error
*/
addListener(event: string, listener: (...args: any[]) => void): this;
addListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this;
addListener(event: "error", listener: (error: Error) => void): this;
on(event: string, listener: (...args: any[]) => void): this;
on(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this;
on(event: "error", listener: (error: Error) => void): this;
once(event: string, listener: (...args: any[]) => void): this;
once(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this;
once(event: "error", listener: (error: Error) => void): this; prependListener(event: string, listener: (...args: any[]) => void): this;
prependListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this;
prependListener(event: "error", listener: (error: Error) => void): this;
prependOnceListener(event: string, listener: (...args: any[]) => void): this;
prependOnceListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this;
prependOnceListener(event: "error", listener: (error: Error) => void): this;
}

在源码中我们可以看出,fs模块提供了不少的事件,如“error”、“change”等。 通过事件监听,我们可以方便的监控文件操作时的状态,例如可以监听error事件来判断文件读写是否出错。

对流的操作一般由以下几种:

1、读取流

 var fs = require("fs");
var readerStream = fs.createReadStream('test.txt');//读取test文件

2、写入流

 var fs = require("fs");
var writerStream = fs.createWriteStream('test.txt');
writerStream.write('test_data','UTF8');//写入test文件

3、管道流,即输出流转入输入流(可用于文件下载)

 var fs = require("fs");
var readerStream = fs.createReadStream('input.txt');
var writerStream = fs.createWriteStream('output.txt');
readerStream.pipe(writerStream);

4、链式流, 链式是通过连接输出流到另外一个流并创建多个流操作链的机制

 var fs = require("fs");
var zlib = require('zlib');//压缩及解压缩模块
//压缩input.txt到input.txt.gz
fs.createReadStream('input.txt')
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream('input.txt.gz'));

利用流的特性我们写一个文件下载的范例:

 const fs = require("fs");
module.exports = {
downloadApp(req, res, next) {
var name = "XXX.apk";
var path = 'download_file/' + name;
fs.exists(path, function (exists) {
if (exists) {
var size = fs.statSync(path).size;
var f = fs.createReadStream(path);
f.on('error', function (err) {//监听error事件判断文件读写是否出错
console.log(err.stack);
//此处可以记log
});
res.writeHead(200, {
'Content-Type': 'application/force-download',
'Content-Disposition': 'attachment; filename=' + name,
'Content-Length': size
});
f.pipe(res);//将读取的文件流写入输出流
}
});
},
}

Node.js的文件操作

Node.js中有对文件操作功能非常丰富的模块,就是在上文中我们提到的fs模块。fs模块的所有文件操作函数都提供同步和异步,不过通常使用异步较多(非阻塞特性)。

 var fs = require("fs");
// 异步读取
fs.readFile('test.txt', function (err, data) {
if (err) {
return console.error(err);
}
console.log("异步读取: " + data.toString());
});
// 同步读取
var data = fs.readFileSync('test.txt');
console.log("同步读取: " + data.toString());

除此之外,fs提供了众多操作,以下是其中一部分:

fs.open(path[, flags[, mode]], callback)

fs.write(fd, buffer[, offset[, length[, position]]], callback)

fs.writeFile(file, data[, options], callback)

当 flag 选项采用字符串时,可用以下标志:

  • 'a' - 打开文件用于追加。如果文件不存在,则创建该文件。
  • 'ax' - 与 'a' 相似,但如果路径已存在则失败。
  • 'a+' - 打开文件用于读取和追加。如果文件不存在,则创建该文件。
  • 'ax+' - 与 'a+' 相似,但如果路径已存在则失败。
  • 'as' - 以同步模式打开文件用于追加。如果文件不存在,则创建该文件。
  • 'as+' - 以同步模式打开文件用于读取和追加。如果文件不存在,则创建该文件。
  • 'r' - 打开文件用于读取。如果文件不存在,则出现异常。
  • 'r+' - 打开文件用于读取和写入。如果文件不存在,则出现异常。
  • 'w' - 打开文件用于写入。如果文件不存在则创建文件,如果文件已存在则截断文件。
  • 'wx' - 与 'w' 相似,但如果路径已存在则失败。
  • 'w+' - 打开文件用于读取和写入。如果文件不存在则创建文件,如果文件已存在则截断文件。
  • 'wx+' - 与 'w+' 相似,但如果路径已存在则失败。

Node.js入门教程 第四篇 (流及文件操作)的更多相关文章

  1. Node.js入门教程 第五篇 (Express框架)

    Express框架 Express是适用于Node.js web的框架,提供了大量实用功能,例如路由功能及http功能. Express 框架核心特性: 可以设置中间件来响应 HTTP 请求. 定义了 ...

  2. Node.js入门教程 第三篇 (模块及路由)

    Node.js的模块 Node.js的模块与传统面向对象的类(class)不完全相同.Node.js认为文件即模块,即一个文件是一个模块.单一文件一般只专注做一件事情,保证了代码的简洁性. 创建模块: ...

  3. Node.js入门教程 第六篇 (连接使用MySql)

    连接使用MySql 安装MySql模块: npm install mysql 创建连接: const mysql = require('mysql') // 连接 mysql 服务器 const co ...

  4. 【特别推荐】Node.js 入门教程和学习资源汇总

    这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...

  5. Node.js 入门教程和学习资源汇总

    这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...

  6. 极简 Node.js 入门 - 4.3 可读流

    极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...

  7. 极简 Node.js 入门 - 4.4 可写流

    极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...

  8. node.js 入门教程(beginnder guide

    非常好的教程: node入门: JavaScript与Node.js JavaScript与你 简短申明 服务器端JavaScript “Hello World” 一个完整的基于Node.js的web ...

  9. Node.js入门教程:Node.js如何安装配置并部署第一个网站

    前言:作为一个资深的前端开发人员,不懂的Node.js 那你绝对是不能跟别人说你是资深的前端程序猿滴! 今天洋哥就来和大家一起学习被大牛称之为前端必学的技能之一Node! 那么Node到底是什么呢? ...

随机推荐

  1. Linux系统调用表(x86_64)

    内核版本 Linux 4.7 Note:64位系统中,不再使用int 0x80来进行系统调用,取而代之的是syscall指令 %rax System call %rdi %rsi %rdx %r10 ...

  2. Loadrunner 11 的安装

    安装包可以直接在我的百度网盘下载,这里用的是LR11的版本.电脑系统是win7 链接: https://pan.baidu.com/s/1OApfUemG3oVjLUE79qaikw 提取码: 7n3 ...

  3. 致初学者(一): HDU 2000~ 2013题解

    对于开始学习C语言程序设计或C++程序设计面向过程部分的同学来说,利用在线OJ网站进行实践训练,对提高自己的编程能力很有好处.国内外OJ网站很多,每个都去看看,去刷个题,是不现实的,也没必要.即使一个 ...

  4. Docker下kafka学习三部曲之一:极速体验kafka

    Kafka是一种高吞吐量的分布式发布订阅消息系统,从本章开始我们先极速体验,再实战docker下搭建kafka环境,最后开发一个java web应用来体验kafka服务. 我们一起用最快的速度体验ka ...

  5. 松软科技课堂:SQLUNION和UNIONALL操作符

    SQL UNION 操作符 UNION 操作符用于合并两个或多个 SELECT 语句的结果集. 请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列.列也必须拥有相似的数据类型.同时,每 ...

  6. Cabloy-CMS:动静结合,解决Hexo痛点问题(进阶篇)

    前言 前一篇文章 介绍了如何通过Cabloy-CMS快速搭建一个博客站点. 这里简单介绍Cabloy-CMS静态站点的渲染机制,更多详细的内容请参见https://cms.cabloy.com 渲染规 ...

  7. 理解setState

    近来在学习react源码, 最初是直接从入口一行一行的看, 结果跟着调用的函数跳转来跳去头都晕了. 后来决定带着一个目的去看源码, 每次看只研究一个东西. 一开始最想了解的就是充满魔性的setStat ...

  8. GDB 调试指南

    本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复 「1024」 即可领取,欢迎大家关注,二维码文末可以扫. 00 介绍 ...

  9. C++ 变量判定的螺旋法则

    C++ 中一个标识符配合着各种修饰界定符,使得标识符的本意不那么直观一眼就能看出,甚至需要仔细分析,才能知道该标识符的具体你含义. 比如: void (*signal(int, void (*fp)( ...

  10. 品Spring:负责bean定义注册的两个“排头兵”

    别看Spring现在玩的这么花,其实它的“筹码”就两个,“容器”和“bean定义”. 只有先把bean定义注册到容器里,后续的一切可能才有可能成为可能. 所以在进阶的路上如果要想走的顺畅些,彻底搞清楚 ...