/ node

Node.js中的数据处理IO-Stream-1

标签:node javaScript

Buffer作为Node.js中数据在内存中具体表现形式。而在现实中数据基本上都不是事由程序员手动输入内存中,而是存储在外部的硬盘或是由HTTP响应回来的数据流。面对这些流式数据,在Node.js就需要Stream模块来处理,并把这些数据写入内存中去。

数据流通常可分为:可读、可写、或即可读有可写的内存结构,而流的目的通常不仅仅是将数据读到内存中而是提供一种从一个地方传送数据到另一个地方的通用机制。

我们可以这样来理解Stream:数据从一个地方到另一个地方的过程,可写流就是 就是向你写的程序来的数据流,因为你需要去读它;可写流则恰好相反,你发出的需要的别的地方去的流为可写流,因为数据要到别的地方使用(存储或是用于别的进程);双工流就是可写流和可读流的合并,用于双向传输数据;转换流是双工流的升级版,进行了一定的封装,用于处理一个系统到另一个系统的数据(你都不属于这两个系统)。

下面为创建和使用Readable(可读)、Writeable(可写)流的过程。而Duplex(双工)、Transform(转换)会在下一节详述。

Readable流

主要用于读取从其他来源进入应用程序的数据。

  • 客户端的HTTP请求
  • 服务器的HTTP响应
  • fs读取流
  • zlib
  • cropto(加密)流
  • TCP套接字
  • 子进程的stdoutstderr
  • process.stdin

适用于Readable流对象的方法

//从流中读取数据。这些数据可以是String、Buffer或者是null
read([size]);
//设置从read()请求读取返回String时使用的编码
setEncoding(encoding);
//暂停从该对象发出的data事件
pause()
//恢复从该对象发出的data事件
resume();
//把流的输出传输到一个由destination指定的Writable流对象,options之后会提到
pipe(destination,[options]);
//从Writable目的地断开这一对象
unpipe([destination]);

Readable对外留下的钩子(事件)

  • readable:在数据块可以从流中读取的时候发出。
  • data:流分块的读取对应内容,当某块内容读取完成时,触发该事件。
  • end:当数据将不再被提供时,也就是数据读取完毕时触发。
  • close:当底层资源,如文件,已关闭时触发。
  • error:流读取错误是触发。

就像数字的迭代器一样,Readable也可以自定义,实现两步即可:

1.继承Readable流的功能。

var util = require('util');
util.inherits(MyReadableStream,stream.Readable);

2.创建对象调用实例

stream.Readable.call(this.opt);

3.实现一个调用push()来输出Readable对象中的数据的_read()方法。push()调用应推入的是一个StringBuffer,或者null

//eg
var stream = require('stream');
var util = require('util');
util.inherits(Answers, stream.Readable);
function Answers(opt) {
  stream.Readable.call(this, opt);
  this.quotes = ["yes", "no", "maybe"];
  this._index = 0;
}
Answers.prototype._read = function() {
  if (this._index > this.quotes.length){
    this.push(null);
  } else {
    this.push(this.quotes[this._index]);
    this._index += 1;
  }
};
var r = new Answers();
console.log("Direct read: " + r.read().toString());
r.on('data', function(data){
  console.log("Callback read: " + data.toString());
});
r.on('end', function(data){
  console.log("No more answers.");
});

//console:
//Direct read: yes
//Callback read: no
//Callback read: maybe
//No more answers.


Writable流

Writable流旨在提供把数据写入一种可以轻松地在代码的另一个区域被使用的形式的机制。大白话就是:把数据输入到别的地方,如硬盘、其他进程···

  • 客户端上的HTTP请求
  • 服务器上的HTTP响应
  • fs写入流
  • zlib
  • crypto
  • TCP套接字
  • 子进程的stdin
  • process.stdoutprocess.stderr

适用于Writable流对象的方法

//将数据块写入流,encoding用于设置编码,当数据写入完毕会触发callback。写入成功返回true,失败false
write(chunk,[encoding],[callback]);
//write方法的功能都有,同时将流置于不再接受数据的状态,并发送finish事件
end([chunk],[encoding],[callback]);

Writable对外留下的钩子(事件)

  • drain:当write()调用返回false后,当准备好开始写更多的数据时,发出此事件。
  • finish:当end()Writable对象上调用,所有的数据都被刷新,并且不会有更多的数据将被接受时发出次事件。
  • pipe:当pipe()方法在Readable流上被调用,以添加此Writable为目的时,发出此事件。
  • unpipe:当unpipe()方法在Readable流上被调用,以删除此Writable为目的时,发出此事件。

当然,Writable也可以自定义实现,步骤和Readable差不多。

var stream = require('stream');
var util = require('util');
util.inherits(Writer, stream.Writable);
function Writer(opt) {
  stream.Writable.call(this, opt);
  this.data = new Array();
}
Writer.prototype._write = function(data, encoding, callback) {
  this.data.push(data.toString('utf8'));
  console.log("Adding: " + data);
  callback();
};
var w = new Writer();
for (var i=1; i<=5; i++){  
  w.write("Item" + i, 'utf8');
}
w.end("ItemLast");
console.log(w.data);

//console
//Adding: Item1
//Adding: Item2
//Adding: Item3
//Adding: Item4
//Adding: Item5
//Adding: ItemLast
//['Item1','Item2','Item3','Item4','Item5','ItemLast']

小结:钩子对于数据处理将会非常的有用处,事件机制永远都是JavaScript的重心。