Node.js开发入门—Stream(流)基本用法详解

本文详细介绍了Node.js中Stream模块的四种类型:可读流、可写流、双工流和变换流。通过示例代码解释了每种流的工作原理及其应用场景,包括如何在流动模式和暂停模式之间进行切换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Stream是Node.js中非常重要的一个模块,应用广泛。

先了解什么是流

流是一组有序的,有起点和终点的字节数据传输手段,是一个抽象接口,从而实现了从一个地方流到另一个地方。

Stream 有四种流类型:

  • Readable - 可读的流 (例如fs.createReadStream()).
  • Writable - 可写的流 (例如fs.createWriteStream()).
  • Duplex - 双工流 (可读写的流)(例如 net.Socket).
  • Transform - 变换流:在读写过程中可以修改和变换数据的 Duplex 流 (例如zlib.createDeflate()).

下面就一一介绍Stream的四种类型:

可读流(Readable streams)

Readable流提供了一种将外部来源的数据读入到应用程序的机制。

可读的流有两种模式:flowing (流动模式)和 paused(暂停模式)

在 flowing 模式下,可读流自动从系统底层读取数据,并通过 EventEmitter 接口的事件尽快将数据提供给应用,直到来源的数据耗尽

在 paused 模式下,必须显式调用 stream.read() 方法来从流中读取数据片段, 你不要它就在那儿耗着等你。暂停模式是一个可读流实例被创建时的默认模式

暂停模式和流动模式可以互相转换。

所有初始工作模式为 paused 的 Readable 流,可以通过下面三种途径切换到 flowing 模式:

  1. 监听 'data' 事件
  2. 调用 stream.resume() 方法
  3. 调用 stream.pipe() 方法将数据发送到 Writable

可读流可以通过下面途径切换到paused 模式:

  1. 如果不存在管道目标(pipe destination),可以通过调用 stream.pause() 方法实现。
  2. 如果存在管道目标,可以通过取消'data' 事件监听,并调用 stream.unpipe() 方法移除所有管 道目标来实现。
所有的流都是是基于事件eventEmitter,通过发射事件来反馈流的状态。 流的传输过程默认是以buffer的形式传输的,除非你给他设置其他编码形式.

我们来举一个简单的Readable的例子。

/**可读流**/
//首先建立一个1.txt文件,里面写有1234567890的字符
let fs = require('fs');//引入一个fs文件
//创建一个可读流
let rs = fs.createReadStream('./1.txt',{
    flags:'r',//我们要对文件进行何种操作,r是读文件
    encoding:'utf8',//设置编码
    start:0,//从索引为0的位置开始读
    end:7,//读到索引为8结束
    highWaterMark:3// highWaterMark缓冲区大小,highWaterMark缓存区默认大小64kb
});
//先触发文件打开事件 
rs.on('open',function () {
    console.log('文件打开');
});
//监听它的data事件,当你一旦开始监听data事件的时候,流就可以读文件的内容并且发射data
//默认情况下,当你监听data事件之后,会不停的读数据,然后触发data事件,
//触发完data事件后再次读数据
rs.on('data',function (data) {
    console.log(data);
    rs.pause();//暂停读取和发射data事件
    setTimeout(function(){
    rs.resume();//一秒后恢复读取并触发data事件,直到文件读取完了。
    },1000);
});
//将在流中有数据可供读取时触发
rs.on('readable',function(){
    //读取一个字段,如果可读流发现你要读的字节小于等于缓存字节大小,则直接返回
  //当你读完指定的字节后,如果可读流发现剩下的字节已经比最高水位线小了。
//则会立马再次读取填满 最高水位线
    let char = rs.read(1);
    console.log(char);
});

//如果读取文件中出错了,会触发error事件
rs.on('error',function (err) {
    console.log(err);
});
//如果文件的内容读完了,会触发end事件
rs.on('end',function () {
    console.log('读完了');
});
//如果文件的内容读完了,会触发close事件
rs.on('close',function () {
    console.log('文件关闭');
});

/*输出结果
文件打开
123
4
4
56
7
7
8
读完了
文件关闭*/
复制代码

注:readable:在数据块可以从流中读取的时候发出。它对应的处理器没有参数,可以在处理器里调用read([size])方法读取数据。

read([size]):该方法可以接受一个整数作为参数,表示所要读取数据的数量,然后会返回该数量的数据。如果读不到足够数量的数据,返回null。如果不提供这个参数,默认返回系统缓存之中的所有数据。

可写流(Writable streams)

实现了stream.Writable接口的对象来将流数据写入到对象中

Writable流的write(chunk[,encoding] [,callback])方法可以把数据写入流中。

chunk是我们即将要写入的数据,通常是一个buffer或String对象

encoding设置指定字符串的编码格式

callback是在完成处理数据块后需要调用的函数。这是写数据成功与否的标志。若要发出故障信号,请用错误对象调用回调函数

write方法返回布尔值,默认是true,代表当前缓冲区(highWaterMark)的状态,如果缓冲区的状态已经到最高水位线, write 方法会返回false。一旦我们确认方法返回了false后,应该立刻停止调用 write 方法,直到缓冲器中的数据被清空为止。此时会调用 'drain' 事件,在 'drain' 事件触发前, 不能写入任何数据块。

我们来举一个简单的Writable的例子。

let fs = require('fs');
//创建一个可写流
let ws = fs.createWriteStream('./1.txt',{
    flags:'w',//我们要对文件进行何种操作
    mode:0o666,
    autoClose:true,//是否自动关闭文件
    encoding:'utf8',//设置编码
    start:0,//从第个索引开始写
    highWaterMark:3// highWaterMark缓冲区大小,highWaterMark读取缓存区默认的大小64kb
});

let i = 6;
function write(){
//如果缓存区已满 ,返回false,如果缓存区未满,返回true
//如果能接着写,返回true,如果不能接着写,返回false
//按理说如果返回了false,就不能再往里面写了,但是如果你真写了,也不会丢失,会缓存在内存里。
//等缓存区清空之后再从内存里读出来

    let flag = true;
    while(flag && i>0){
        flag = ws.write((i--)+'');
        console.log('flag',flag);
        console.log(i);
    }
}
write();
ws.on('error',function () {
    console.error('error');
});
ws.on('drain',function () {
    console.log('drain');
    write();
});
/*输出结果
flag true
5
flag true
4
flag false
3
drain
flag true
2
flag true
1
flag false
0
drain
*/
复制代码

小编先写到这里,后续在给大家介绍另两种方法

扩展

Nodejs Stream 数据流使用手册


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值