第一个stream例子
const fs = require('fs');
const stream = fs.createWriteStream('./big_file.txt');
for (let i = 0; i < 1000000; i++) {
stream.write(`这是第${i}行内容\n`);
}
stream.end(); //别忘记关闭stream
console.log('打完了');
分析
打开流,多次往里面塞内容,关闭流
就是可以多次往文件里写内容,且不覆盖上次的内容
最终得到一个24M的文件
Stream-流
stream就像是水管
stream.write就好像水龙头往水管里注入的水(数据)
每次写的小数据叫做chunk(块)
产生数据的水龙头叫做source(源头)
得到数据的那一段叫做sink(水池)
第二个stream例子
const fs= require('fs')
const http= require('http')
const server = http.createServer()
server.on('request',(request,response)=>{
fs.readFile('./big_file.txt',(err, data)=>{
if (err)throw err
response.end(data)
console.log("打完了")
})
})
server.listen(8888)
Node.js会占用大量内存
第三个stream例子
const fs= require('fs')
const http= require('http')
const server = http.createServer()
server.on('request',(request,response)=>{
const stream = fs.createReadStream("./big_file.txt")
stream.pipe(response)
})
server.listen(8888)
分析
Node.js占用较低的内存
文件stream和response stream 通过管道相连
管道
两个流可以用一个管道
stream1 的末尾连接上stream2的开端
只要stream1有数据,就会流到stream2
常用代码
stream1.pipe(stream2)
链式操作
a.pipe(b).pipe(c)
等价于
a.pipe(b)
b.pipe(c)
管道可以通过事件去实现
//一有数据就塞给stream2
stream1.on('data',(chunk)=>{
stream2.write(chunk)
})
//stream1停了,就停了stream2
stream1.on('end',()=>{
stream.end()
})
Stream 对象的原型链
s=fs.createReadStream(path)
那么它的对象层级为
自身属性(由fs.ReadStream构造)
原型:stream.Readable.prototype
二级原型:stream.Stream.prototype
三级原型:events.EvebtEmitter.prototype
四级原型:Object.prototype
Stream对象都继承了EventEmitter
支持的时间和方法
| Readable Stream | Writable Stream | |
|---|---|---|
| 事件 | data ,end ,error ,close ,readable | drain ,finish ,error ,close ,pipe ,unpipe |
| 方法 | pipe() ,unpipe(),wrap() ,destroy() ,read() ,unshift() ,resume() ,pause() ,isPaused() ,setEncoding | write() ,destroy() ,end() ,crok() ,uncrok() ,setDefaultEncoding() |
Stream分类
| 名称 | 特点 |
|---|---|
| Readable | 可读 |
| Writable | 可写 |
| Duplex | 可读可写(双向) |
| Transfor | 可读可写(变化) |
Readable Stream
静止态paused和流动态flowing
默认处于paused态
添加data事件监听,它就变成flowing态
删掉data事件监听,它就变成paused态
pause()可以将它变成paused
resume()可以将它变为flowing
Writable Stream
drain 干枯事件
表示可以加点水了
我们调用stream.write(chunk)的时候,可能会得到false
false的意思表示写入太快,数据造成积压
是这个时候就不能继续写入了,要监听drain事件
等drain事件触发了,我们才能继续write
finish 事件
调用stream.end()之后,而且缓冲区的数据已经传给底层系统之后,再触发finish事件。
创建一个Writable Stream
const Writable = require('stream').Writable;
const outStream = new Writable({
write(chunk, encoding, callback) {
console.log(chunk.toString());
callback();
}
});
process.stdin.pipe(outStream);
创建一个Readable Stream
const Readable = require('stream').Readable;
const inStream = new Readable();
inStream.push('ABCDEFG');
inStream.push('abcdefg');
inStream.push(null);
inStream.pipe(process.stdout); //先push再调用
const Readable = require('stream').Readable;
const inStream = new Readable({
read(size) {
this.push(String.fromCharCode(this.currentCharCode++));
if (this.currentCharCode > 90) {
this.push(null);
}
}
});
inStream.currentCharCode = 65;
inStream.pipe(process.stdout); //先调用再push
创建一个Duplex Stream
const Duplex = require('stream').Duplex;
const inoutStream = new Duplex({
write(chunk, encoding, callback) {
console.log(chunk.toString());
callback();
},
read(size) {
this.push(String.fromCharCode(this.currentCharCode++));
if (this.currentCharCode > 90) {
this.push(null);
}
}
});
inoutStream.currentCharCode = 65;
process.stdin.pipe(inoutStream).pipe(process.stdout);
创建Transform Stream
const Transform = require('stream').Transform;
const upperCaseTr = new Transform({
transform(chunk, encoding, callback) {
this.push(chunk.toString().toUpperCase());
callback;
}
});
process.stdin.pipe(upperCaseTr).pipe(process.stdout);