《node-Stream(流)》

577 阅读3分钟

流(stream)是 Node.js 中处理流式数据的抽象接口。 stream 模块用于构建实现了流接口的对象。流有可写流,可读流。

一. 可写流

// 1.js
const fs=require('fs')
const stream=fs.createWriteStream('./big_file.txt')
for(let i=0;i<1000000;i++){
    stream.write(`这是第${i}行数据\n`)
}
stream.end()
console.log('done')

使用fs.createWriteStream就可以创建一个可写的流对象,往后边的文件里写。

调用stream.write(data) 把数据写入流中

可以多次写,写完后,调用stream.end()关闭流

运行node 1.js 就可以看到文件big_file.txt里被写入了内容。

二. 可读流

也可以从一个流中读取数据。

const fs=require('fs')
const stream=fs.createReadStream('./text.txt')
let data=''
stream.on('data',chunk=>{
    data+=chunk
})
stream.on('end',()=>{
    console.log(data)
})

fs.createReadStream('./text.txt') 创建一个可读流,它可以从该文件里以流的形式不断的一点点的读取数据。

这个stream流对象也有on方法,可以监听data事件:当仍有数据可被读取,就读数据。监听end事件,当没有数据可读了,打印出读到的内容。

运行node,就可以打印出text.txt的内容。

一个stream流对象可看成一条水流,但是还没有水。当执行stream.write时,就是在一点一点的把数据data从源头source流向一个水池sink。这个最终流向的水池就是等待被写入内容的文件。

三. 管道流

如果我们有两个流,stream1是可读流,stream2是可写流。想从stream1里读数据,再把数据写到stream2里。这种情况下可以使用管道将两个流连接起来。这样只要stream1里读到了数据,自然就会流到stream2里

代码就是 stream1.pipe(stream2)

const fs=require('fs')
// 创建一个可读流
const read_stream=fs.createReadStream('./input.txt')
// 创建一个可写流
const write_stream=fs.createWriteStream('./output.txt')
// 管道连接。从input文件里读,把读到的数据写入output文件里
read_stream.pipe(write_stream)
console.log('done')

执行结果就是Output文件里被写入了input文件一样的内容。

管道流的实现就相当于监听事件:监听可读流的data事件,一有数据就塞给可写流。再监听可读流的end事件,它没有数据可读了就停止写入流。

read_stream.on('data',(chunk)=>{
	write_stream.write(chunk)
})
read_stream.on('end',()=>{
	write_stream.end()
})

除了文件读写可以是流之外,开启一个http,作为服务器时的响应Response是一个可写流:

const http=require('http')
const fs=require('fs')

const server=http.createServer()
server.on('request',(request,response)=>{
    const stream=fs.createReadStream('./text.txt')
    stream.pipe(response)
})
server.listen('8888')

开启一个server,并监听8888端口。当有人发出请求http://localhost:8888时,这个server就会收到请求。 目的是把text文件响应回去。利用流,创建一个可读流,直接用pipe相连,流到response里。那么这个response对象就是一个流。而且是可写的

多个管道相连就形成了链式流:a.pipe(b).pipe(c) ,由a流向b再流向c。它相当于分开写:a.pipe(b) b.pipe(c)

四. stream对象及原型链

我们创建的可读流或者可写流,这些流对象是什么东西呢?

const fs=require('fs')
const s=fs.createReadStream('./input.txt')
console.log(s);

可以打印出来看一下。但是在node终端,只能看到第一层,s是一个ReadStream对象。怎么看到它的原型链呢?

执行命令node --inspect-brk 6.js node开启监视并打断点。

然后打开chrome一个标签页,开发者工具。等一会会看到出现一个绿色的node小图标,点开。就会看到6.js文件的代码:在打印s那里打个断点,不然程序会执行完毕看不到原型链。然后按左下方第二个单步执行图标,执行完log

点开Console 控制台,就可以看到它的原型链:

从下往上分别是:

ReadStream(自身属性)-> 原型Readable -> 二级原型Stream -> 三级原型EventEmitter -> Object