代码改变世界

Nodejs读写流

2014-08-17 21:11  king0222  阅读(2722)  评论(0编辑  收藏  举报

Nodejs读写流

流的传输过程默认是以buffer的形式传输的,除非你给他设置其他编码形式,
例如下面代码第二部分中,我们设置了流以utf8的编码形式进行传输:

 1 var readable stream1 = ...
 2 readable stream1.on('data', function(data) {
 3 // data is a buffer;
 4 console.log('got this data:', data);
 5 });
 6 var readable stream2 = ...
 7 readable stream2.setEncoding('utf8');
 8 readable stream2.on('data', function(data) {
 9 // data is a utf8-encoded string;
10 console.log('got this data:', data);
11 });

流的传输过程是可以停止的,用pause()方法便可以暂停流的传输过程,
同理,流的传输过程还有对应的恢复方法,即重新恢复传输过程,采用resume()方法。

stream.pause();
stream.resume();

如果我们希望在流传输完成后进行某些某些操作,我们可以监听他的end事件

1 var readable stream = ...
2 readable stream.on('end', function() {
3     console.log('the stream has ended');
4 });

1.使用可写流(WRITABLE STREAMS)
所谓可写流,就是可以一个允许你写入数据的对象。
最简单的操作可写流的方式就是使用write方法:
var writable_stream = ...;
writable_stream.write('this is an UTF-8 string');
你传入一个字符串形式作为参数的话,默认就是utf8编码的,当然你也可以再第二个参数中传入你想要的编码形式:
var writable_stream = ...;
writable_stream.write('7e3e4acde5ad240a8ef5e731e644fbd1', 'base64');
又或者,你也可以将buffer写入可写流中:
var writable_stream = ...;
var buffer = new Buffer('this is a buffer with some string');
writable_stream.write(buffer);
在这里需要注意的一点是,在写进流的过程中,node并不一定能够及时的将数据写入kernel buffer,这个时候Node就会
将数据保存在缓冲队列中,在适当的时候才会重新将数据写入到正确的位置,这个时候可能需要监听一些事件来知道
何时那些缓冲队列的数据被重新写入了,该事件就是drain.

1 var writable stream = ...;
2 writable stream.on('drain', function() {
3     console.log('drain emitted');
4 });

2.创建文件系统流

var fs = require('fs');
var rs = fs.createReadStream('/path/to/file');
上面的代码创建了一个可读流,我们可以再传入第二个参数,第二个参数为一个json对象形式的参数,具有以下几个配置项:

1 {
2     encoding:'xx',
3     fd:'xx', //文件描述
4     bufferSize:'xx',
5     start:'xx',
6     end:'xx'
7 }

如果你已经打开了一个文件,你可以读的到他的文件描述,则可以在第二个参数中传入这个文件描述:

1 ar fs = require('fs');
2 var path = '/path/to/my/file';
3 fs.open(path, 'r', function(err, fd) {
4     fs.createReadStream(null, {fd: fd, encoding: 'utf8'});
5     fs.on('data', console.log);
6 });

3.创建文件可写流

var fs = require('fs');
var rs = fs.createWriteStream('/path/to/file', options);
第二个参数默认值如下:

1 { flags: 'w',
2 encoding: null,
3 mode: 0666 }

你可以创建一个可以接受utf8编码的文件可写流:
var fs = require('fs');
var rs = fs.createWriteStream('/path/to/file', { encoding: 'utf8' });

4.理解网络流
一个TCP连接既是可读流,又是可写流;而Http连接则不同,一个http request对象是可读流,而http response对象则是可写流。
5.理解客户端缓慢的问题
首先,服务器读取文件的速度是很快的,然而客户端写入的速度确不能跟服务器读取的速度一致,这就对导致服务器
读取数据的时候无法及时传送到客户端,就会采取缓存策略。这会带来一个严重的问题,服务器内存爆满。
为了解决这个问题,我们需要监听客户端写入的事件是否正常,如果可以正常写入则服务器端则继续读取数据并传送。
在上面提到了流的传输过程是可以中断和继续的,并且有drain事件可以监听的到,我们可以利用这些特性来优化我们的
读写流的过程。一般情况下,如果我们不处理这种问题的话,代码像下面这样是很容易出现问题的:

1 require('http').createServer(function(req, res) {
2     var rs = fs.createReadStream('/path/to/big/file');
3     rs.on('data', function(data) {
4         res.write(data);
5     });
6     rs.on('end', function() {
7         res.end();
8     });
9 }).listen(8080);

代码中没有进行任何中断和持续的处理,如果写入流的过程能够正常的话,write()方法能够返回true,否则会返回false;
我们可以通过这样的API来优化我们的代码:

 1 require('http').createServer( function(req, res) {
 2     var rs = fs.createReadStream('/path/to/big/file');
 3     rs.on('data', function(data) {
 4         if (!res.write(data)) {
 5             rs.pause();
 6         }
 7     });
 8     res.on('drain', function() {
 9         rs.resume();
10     });
11     rs.on('end', function() {
12         res.end();
13     });
14 }).listen(8080);

上面的过程在读写流的时候是很常见的,因此Node给出了一个通用的方法,就是pipe();该方法解决了上述所提到的这些问题。

1 require('http').createServer(function(req, res) {
2     var rs = fs.createReadStream('/path/to/big/file');
3     rs.pipe(res);
4 }).listen(8080);

默认情况下,数据传送完成后就会调用end()方法,如果你希望调用自定义的end的话,则可以添加一个参数给他:

1 require('http').createServer(function(req, res) {
2     var rs = fs.createReadStream('/path/to/big/file');
3     rs.pipe(res, { end: false });
4     rs.on('end', function() {
5         res.write("And that's all, folks!");
6         res.end();
7     });
8 }).listen(8080);