流(Stream)是一个抽象的数据接口,Node.js中很多对象都实现了流,流是EventEmitter对象的一个实例。在类UNIX系统Stream是通过"|"实现对流的操作,node.js中对流的操作是通过.pipe()方法。按流的可操作性有可读流和可写流之分。Stream 是一个可以重复使用的统一的接口,通过抽象的Stream接口可以实现控制对象之间Stream的读写平衡。
1.可读流操作
在创建或者获取一个可读流(如:读取一个文件后、收到一个client端HTTPt responses后)之后,可以对其进行一些控制和操作。例如:可以通过暂停和恢复来控制数据的流动、可以在收到数据时得到data通知、可以在流终止时关闭传输。
1.1 'data' 事件等待数据传输
流会以块为单位发送二进制数据,通过监听"data"事件,可以在数据传输时通知及本次的数据块。示例如下:
var readable = getReadableStreamSomehow(); //getReadableStreamSomehow()是一个获得可读流的方法 readable.on('data', function(chunk) { //本次得到的数据块chunk console.log('got %d bytes of data', chunk.length); });
1.2 流的暂停与恢复
可读流就像一个阀门,可以通暂停来数据流动,可以通resume()方法恢复传输。示例如下:
var readable = getReadableStreamSomehow(); readable.on('data', function(chunk) { console.log('got %d bytes of data', chunk.length); readable.pause(); //暂停 console.log('接下来的1秒数据传输将会暂停'); setTimeout(function() { console.log('数据传输恢复'); readable.resume(); //恢复 }, 1000); });
1.3 流传输结束
流传输结果后会收到"end"事件,通过监听"end"事件可以进行一些流传输结束后的处理。示例如下:
var readable = getReadableStreamSomehow(); //getReadableStreamSomehow()是一个获得可读流的方法 readable.on('data', function(chunk) { //本次得到的数据块chunk console.log('got %d bytes of data', chunk.length); }); readable.on('end', function() { console.log('数据传输结束'); });
1.4 Node.js中的可读流有
- client端的http responses
- server端的http requests
- fs 中的可读 streams
- zlib 模块的 streams
- crypto 模块的 streams
- tcp sockets
- child process 模块的 stdout 和 stderr
- process.stdin
2.可写流操作
可写流可能会是一个文件,也可能是一个TCP或HTTP的网络连接等。通过对可写流的操作,可以实现向传输对象写入一些数据等。
2.1 将数据写入可写流
向流写入数据时,可以传送缓冲区Buffer数据或字符串。写入时,可设置第二个可选参数设置数据编码。示例如下:
var file = fs.createWriteStream('example.txt'); file.write('itbilu.com'); //写入数据时,可以设置编码格式 file.write('aXRiaWx1LmNvbQ==', 'base64'); //写缓冲区Buffer数据 var buf = new Buffer('itbilu.com'); file.write(buf);
2.2 可写流的完成与清空
向流写入数据时,你会知道缓冲区数据是否被立即刷新,如果没有被刷新数据会被存储到内存中。在流成功刷新挂起的缓冲区时,stream会发送“drain”事件。写入完成后会发送“finish”事件。示例如下:
var writer = fs.createWriteStream('example.txt'); //假设这是一个可能会被挂起的缓冲区 var buf = new Buffer('itbilu.com'); writer.write(buf); //刷新挂起的缓冲区时可写流缓冲区被清空,发送drain事件 writer.on('drain', fuction(){ //对挂起事件的处理 }) //写入完成或调用end()方法后,将会发送finish事件 writer.on('finish', function() { console.error('所有数据已经写入完成.'); });
2.3 Node.js中的可写流有
- 客户端http requests
- 服务器端的http responses
- fs模块的写入流
- zlib streams
- crypto streams
- tcp sockets
- child process模块的stdin
- process.stdout, process.stderr
3.流的使用示例
创建一个http服务器,每当有请求进入时,从文件中读取一个可读流,将流转接到Http response可写流中。
var http=require('http'); var fs =require('fs'); //创建http服务 var server=http.createServer(); //监听request事伯 server.on('request',function (req, res) { //每当有请求进入时,fs会从demo.mp3文件创建一个可读流,并将数据pipe()接入到res响应流中 res.writeHead(200,{'Content-Type':'audio/mp3'}); var rs=fs.createReadStream('/home/liuht/demo.mp3'); rs.pipe(res); }) //启动服务 server.listen(3333);
4.Buffer、fs、Stream之间的关系
Buffer是数据缓冲区对象,是二制数据在内存中的表现形式。Buffer中的数据可以按stream的形式传递到其它对象中。
fs是文件操作对象,文件是数据在硬盘上的表现形式。fs读出数据后会放入Buffer中才能对数据进行操作。写入数据前,数据也应该放到Buffer对象中再写入到文件中。fs读写文件时,数据是按流(stream)形式进行传输的。
stream是数据传输对象,如果需要在传输过程中对数据进行处理,则需要处理流数据。如果把文件比做装数据的容器,那流是容器间数据传输的一个过程,流传输的对象就是Buffer(二进制)数据。