Stream 流
stream 是一个抽象接口,node 中有很对象实现了这个接口。例如,对http 服务器发起请求的request 对象就是 一个stream,还有stdout(标准输出)。Stream 可以是只读、可写,也可以同时可读可写。所有的Stream 对象 都是EventEmitter 的实例。
Readable Stream 可读流
可读流:用来提供数据,外部来源的数据可被存储到内部的Buffer里面缓存起来。
一个可读流有如下方法、成员、和事件。
1.Event: ‘data’
‘data’事件的参数是Buffer(默认情况下),如果调用过setEncoding()方法,则参数为一个字符串。
2.Event: ‘end’
此事件在流遇到EOF(在TCP 中为FIN)时被触发,表示该流不会再有数据(不会再次触发’data’事件)。如果该流 也是可写流,则它还可以继续写入。
3.Event: ‘error’
在收取数据出错时被触发。
4.Event: ‘close’
内部的文件描述符被关闭时被触发,并不是所有的流都会触发此事件。(例如,一个进入的(incoming)HTTP 请 求将不会触发’close’事件)。
5.Event: ‘fd’
当数据流接收到文件描述符信息时触发该事件(一个文件数据流包含两部分信息:文件描述符信息和文件的数 据信息)。本事件只支持Unix 数据流,其他类型的流不会触发该事件。
6.stream.readable
一个布尔值,默认为true。当遇到错误或流读到结尾或者调用destory()函数后,该值被设置为false。
7.stream.setEncoding(encoding)
该函数设置data 事件返回字符串而不是Buffer 对象。编码类型可以设置为”utf8”,”ascii”或”base64”。
8.stream.pause()
暂停触发data 事件。
9.stream.resume()
恢复触发’data’事件。
10.stream.destroy()
关闭内部的文件描述符。这样该流将不会再触发任何事件。
示例代码如下:
var fs = require('fs');
var readStream = fs.createReadStream('stream_Copy_Logo.js');
var n = 0;
readStream
.on('data', function(chunk){
console.log("data emit");
n++;
console.log(Buffer.isBuffer(chunk));
// console.log("stream" + chunk.toString());
readStream.pause();
console.log("Data Pause!");
setTimeout(function(){
readStream.resume();
console.log("Data resume!");
},3000);
})
.on('readable', function(){
console.log('readable');
})
.on('end', function(){
console.log("n"+n);
console.log("end");
})
.on('close', function(){
console.log('close');
readStream.close();
})
11.Event: ‘pipe’
‘pipe’事件时发出stream.pipe()方法读取流,添加这个可写至目的地。
pipe()方法会自动监听data和end事件,源端数据会源源不断地发送至pipe链末端,除此以外,pipe方法还可以自动控制后端压力;在目的地写入数据缓慢时,node可以将尽可能少的缓存放置于内存中;通过对内存空间的调度就能实现自动控制流量;并且数据在pipe时,只要pipe链末端真正需要数据时数据才会从源头被取出
const writer = getWritableStreamSomehow();
const reader = getReadableStreamSomehow();
writer.on('pipe', (src) => {
console.error('something is piping into the writer');
assert.equal(src, reader);
});
reader.pipe(writer);
边下载边pipe
var http = require("http");
var fs = require("fs");
var request = require('request');
http
.createServer(function(req, res){
// fs.readFile('../Buffer/log.png', function(err,data){
// if(err)
// {
// res.end('file is not exist!');
// }else{
// res.writeHeader(200, {'Context-Type': 'text/html'});
// res.end();
// }
// var readStream = fs.createReadStream("../Buffer/log.png").pipe(res);
//线上图片
request('http://static.mukewang.com/static/img/common/logo.png').pipe(res);
}).listen(8090);
});
Writable Stream 可写流
可写流:用来消费数据,从可读流里获取数据以后,然后对得到Bufer数据进行处理。
一个可写流具备以下方法、成员、和事件。
1.Event: ‘drain’
在一个wrire() 方法被调用并返回false 后触发,表明可以安全的再次写入该stream。
2.Event: ‘error’
在异常发生赤错误时被触发。
3.Event: ‘close’
当底层的文件描述符已终止时发出。
4.stream.writeable
一个boolean 值,缺省为true ,但是在一个’error’产生或是end() / destroy() 被调用后,会变为false 。
5.stream.write(string, encoding=’utf8’, [fd])
使用指定的编码将字符串字符串写入到流中。如果字符串已被刷新到内核缓冲区,返回true。返回false 则表明 内核缓冲区已满,数据将在未来被发送出去。’drain’事件用来通知内核缓冲区何时为空。此方法的默认编码为 ‘utf8’。
如果指定了可选参数fd,它将被当做一个文件描述符并通过流来发送。它只支持UNIX 流,否则会被忽略且没 有任何提示。当用这种方式发送文件描述符时,在流清空之前关闭文件描述符可能导致发送出非法的描述符。
6.stream.write(buffer)
同上,除了使用一个原始缓冲区。
7.stream.end()
通过EOF 或FIN 来终止流。
8.stream.end(string, encoding)
根据指定的编码发送字符串,并通过EOF 或FIN 来终止流。这对于减少发送数据包的数量是非常有用的。
9.stream.end(buffer)
同上,但使用一个缓冲区。
10.stream.destroy()
终止底层的文件描述符,此后流不再发出任何事件。
示例代码:
var fs = require('fs');
// var source = fs.readFileSync('../Buffer/log.png');
// fs.writeFileSync('stream_Copy_Logo.png', source);
var readStream = fs.createReadStream('../Buffer/log.png');
var writeStream = fs.createWriteStream('stream_Copy_Logo2.png');
readStream
.on('data', function(chunk){
if(writeStream.write(chunk) == false) //数据还在缓存中,未写入至目标
{
console.log("still cached!")
readStream.pause();
}
})
.on('end', function(){
writeStream.end();
})
writeStream.on("drain", function(){
console.log("data drains");
readStream.resume();
})
Duplex Stream 双工流
双工流:实现了readable与writeable两个接口;
Transform Stream 转换流
转换流:也是双工的,可读可写,但是不保存数据,只负责处理流经其的Buffer对象。
var Readable = require('stream').Readable;
var Writable = require('stream').Writable;
var readStream = new Readable();
var writeStream = new Writable();
readStream.push("I ");
readStream.push("Love ");
readStream.push("Moc ");
readStream.push(null);
writeStream._write = function(chunk, encode, cb){
console.log(chunk.toString());
cb();
}
readStream.pipe(writeStream);