Stream读写操作

0 阅读2分钟

一.理解Stream


很多人第一次接触 Stream(流) 都会觉得抽象、难懂:到底什么是流?流又能用来做什么?

想象一下:你要把一个巨大鱼塘的水全部抽干
现在给你两个工具:
一个小杯子,一个抽水机

你会选哪个?
肯定选抽水机,对吧?

因为鱼塘太大了,用杯子一杯一杯舀,根本舀不完,还特别慢、特别占地方;
但抽水机不一样,它可以连续不断、一点一点把水抽走,不用一次性把所有水都装起来,也不会因为水太多而装不下。

这个抽水机,就是编程里的 Stream(流)


对应到代码里就是:

  • 以前用 fs 直接一次性读取/写入整个文件 就像用小杯子一次性把一池塘水全装起来
    文件小的时候没问题,但文件一大,内存直接爆掉
  • Stream(流) 就像抽水机 + 水管,它会把文件切成一小段一小段源源不断、连续地读取或写入,不用一次性把整个文件加载到内存里。

大文件、视频、日志、网络数据……只要数据量大,都必须用 Stream,Stream 在 Node.js 里,是 EventEmitter 的实例

二.Stream的使用


在Node中很多功能都是基于流的比如Http,API之间的关系如下:

Node中有四种常见的流,但是其实常用的就只有前两个:

Writable :可以向其写入数据的流,例如fs.createWriteStream()

Readable :可以从中读取数据的流,例如fs.createReadStream()

Duplex :同时为Readable和Writable 例如 net.Socket

Transform :Duplex可以在写入和读取数据时修改或转换数据的流 例如zlib.createDeflate()

Readable

const fs = require("fs");
// 通过流读取文件
const readStream = fs.createReadStream('./aaa.txt',{
    start:3,
    end:20,
    highWaterMark:3
})

// 监听到读取的数据
readStream.on('data',(data)=>{
    console.log(data.toString());
    readStream.pause() // 读取暂停
    setTimeout(()=>{
        readStream.resume(); // 读取恢复
    },2000) 
})

// 监听文件是否打开
readStream.on('open',(fd)=>{
    console.log("通过流将文件打开了~",fd);
})

// 监听文件是否结束,会自动关闭文件流
readStream.on('end',()=>{
    console.log("数据已经读取结束~");
})

// 文件读取结束并且关闭
readStream.on('close',()=>{
    console.log("文件读取完毕并且关闭");
})

Writable

const fs = require("fs");
// 一次性写入内容
const writeStream = fs.createWriteStream('./ccc.txt',{
    flags:'a+', // 写入方式
    start:0, // 写入位置
    encoding:'utf8', // 编码方式
})

// open事件
writeStream.on('open',(fd)=>{
    console.log("文件已经被打开",fd);
})

// 使用可写流对文件进行写入
writeStream.write('kobe byrant',err=>{
    console.log("写入成功!");
})

writeStream.on('finish',()=>{
    console.log("文件写入完成~");
})

// end方法,将最后的内容写入到文件中,并关闭,涉及两个操作
writeStream.end('hhhhh')

// 当写入完成时候手动调用写入方法
writeStream.close()

pipe方法

const fs = require('fs');

// 传统拷贝方式
fs.readFile('./foo.txt',(err,data)=>{
    console.log(data);
    fs.writeFile('./ddd.txt',data,{
        flag:'a+'
    },(err,data)=>{
        if(err) return
        console.log(data,"打印数据信息");
    })
})

// 使用可读流和可写流
const readStream = fs.createReadStream('./foo.txt')
const writeStream = fs.createWriteStream('./foo_copy.txt')
readStream.on('data',(data)=>{
    writeStream.write(data)
})

readStream.on('end',()=>{
    writeStream.close()
})

// 使用pip建立管道来进行文件拷贝
readStream.pipe(writeStream)