读写数据流
流,是Node中的一个抽象概念。
细分可以分为两个:可读流和可写流。他们可以由一些Node对象实现(牢记流只是一个概念)。举几个流的例子:TCP套接字、文件读写。。。
虽然之前也接触过,但本文以更正式的方式介绍。
注意:流是由几个Node对象实现的抽象概念,创建或者获取流的方式取决于使用流的类型。例如,可以基于文件显式地创建一个可读流或者可写流。
但是,服务器端的TCP套接字流只有在客户端连接时才能为你所用。
除了可读流或可写流的特性外,一个对象还可以具有其他一些特殊的属性或行为。例如,文件可读流还包含“路径”属性,而这一属性在其他类型的流中也许并不存在。
使用可读流
可读流就像一个阀门,你可以对其进行控制,比如有暂停和恢复,这个后面会用到。而创建或获取可读流的方法取决于流的类型。
等待数据
通过监听data
事件,每次读取到数据的时候都会触发回调,在回调中可以拿到数据(缓冲区或字符串,取决于编码)。
可以使用stream.setEncoding()
来指定编码格式。
let rs = ...;
rs.on('data', function(data){
// 没有指定编码,默认作为缓冲区传送数据
console.log(data);
})
rs.setEncoding('utf8');
...// 再监听data,就会作为字符串传送数据
注意:因为UT℉-8字符可能是多字节的,所以当你希望获取UT℉-8字符时,也许需要在两个独立的“data”事件发生之后才能获得一个字符,当你将编码格式设置为utf8时,流仅会在一个字符完整的情况下传送它
暂停与恢复流
可以通过暂停,来停止接受数据:
strem.pause
之后,你边不会再接收到‘data’事件,这一特性可以帮你规避缓冲区问题。
注意:暂停流在不同的情况下会被解释成不同的行为。例如,如果是一个文件流,Node就会停止从该文件中读取数据。如果流是一个TCP套接字,Node就不再会读取新的数据包,这会终止从其他终端来的数据包流。其他对象对pause的实现各不相同。
想要恢复,那么使用stream.resume
方法即可。
何时终止流
比如,当一个文件流到达文件末尾的时候,流就会发射end
事件,代表终止。其余的类型,如果流工作结束,也会发射end
事件。
可读流终止之后,你就不会再接收到data
事件了。
使用可写流
可写流是一个抽象概念,可以向其发送数据。
将数据写入流
可以通过传递缓冲区或字符串来写入数据。
let ws = ...;
ws.write("This is the data");
还可以在write
的第二个参数传入编码格式,不然默认utf-8.
也可以传入缓冲区:
const bf = new Buffer('this is the buffer');
ws.write(bf);
发送过程
一旦写入数据,那么数据就会被送到核缓冲区(数据需要排队等待写入,这里就相当于等候室),如果此时没有位置了,就会把多出来的数据传入到一个队列,这个队列在内存中。通过write
函数的返回值可以知道数据正在送往那儿(如果送往核缓冲区,返回true,如果是送往内存,返回false,后面会知道有什么用)。
等待流被清空
Node不会在I/O操作上产生注射,所以它也不会在读写上产生阻塞。比如,在调用写入函数的时候,你可以知道数据正是保存在哪儿。
当流的核缓冲区终于不再满员,成功被刷新,就会发射drain
事件。后面你会看到怎么通过这些操作限制内存增长,提高性能。