node.js 文件流-可读取流

什么是流

  • 流是指数据流动,数据从一个地方缓缓的流动到另一个地方
  • 流是有方向的
    • 可读流:Readable 数据从源头流向内存
    • 可写流:Writable 数据从内存流向源头
    • 双工流:Duplex 数据即可从源头流向内存,又可从内存流向源头

为什么需要流

  • 其他介质和内存的数据规模不一致(内存大小不一致)
  • 其他介质和内存的数据处理能力不一致

文件流

文件流:内存数据和磁盘文件之间的流动

文件流的创建

fs.createReadStream(path[,options])

创建一个文件可读流,用于读取文件内容

  • path:读取的文件路径
  • options:可选配置
    • encoding:编码方式
    • start:起始字节
    • end:结束字节
    • highWaterMark:每次读取的数量
      • 如果encoding有值,该数量表示一个字符数
      • 如果encoding为null,该数量表示字节数
  • 返回:Readable的子类ReadStream
    • 事件:rs.on(事件名,处理函数)
      • open:文件打开事件(文件被打开后触发)
      • error: 文件不存在时触发
      • close:文件被关闭后触发(可通过rs.close手动关闭)或文件读取完成之后自动关闭
      • data:读取到一部分数据后触发(注册data事件后,才会真正的开始读取)(每次读取highWaterMark指定的数量)(回调函数中会附带读取到的数据)
      • end:文件读取完成之后会触发
js 复制代码
const fs = require("fs");
const path = require("path");
const filename = path.resolve(__dirname, "./abc.txt");
fs.createReadStream(filename, {
  encoding: "utf-8",
  highWaterMark: 64 * 1024,
});

rs.on("open", () => {
    console.log("文件被打开了");
});

rs.on("error", () => {
    console.log("出错了!!");
});
rs.on("close", () => {
    console.log("文件关闭了");
});

rs.on("data", chunk => {
    console.log("读到了一部分数据:", chunk);
});

rs.on("end", ()=>{
    console.log("全都读取完毕")
})

fs.createWriteStream(path[,options])

用于创建一个可写入的数据流(Writable Stream)。通过写入流,可以高效地将数据写入文件,特别适用于处理大文件或需要逐步写入数据的场景。

  • path:写入的文件路径
  • options
    • flags:操作文件的方式
    • encoding:编码方式
    • start:起始字节
    • highWaterMark:每次最多写入的字节数
  • 返回:writable的字类WriteStream
    • ws.on(事件名,处理函数)
      • open:文件打开事件(文件被打开后触发)
      • error: 文件不存在时触发
      • close:文件被关闭后触发(可通过rs.close手动关闭)或文件读取完成之后自动关闭
    • ws.write(data):写入一组数据
      • data可以是字符串或Buffer
      • 返回一个Boolean值(true:写入通道没有被填满,接下来的数据可以直接写入,无需排队)(false:写入通道目前已被填满,接下来的数据将写入队列,要特别注意背压问题,因为写入队列时内存中的数据,是有限的)
      • 当写入队列清空时,会触发drain事件
    • ws.end([data])
      • 结束写入,将自动关闭文件(是否自动关闭取决于autoClose默认为true)
      • data是可选的,表示关闭前的最后一次写入
js 复制代码
const fs = require("fs");
const path = require("path");

const filename = path.resolve(__dirname, "./temp/abc.txt");

const ws = fs.createWriteStream(filename, {
  encoding: "utf-8",
  highWaterMark: 2
});

//ws.write("a");
//改进
let i = 0;
//一直写,直到到达上限,或无法再直接写入
function write() {
    let flag = true;
    while (i < 1024 * 1024 * 10 && flag) {
        flag = ws.writs("a"); //写入a,得到下一次还能不能直接写
        i++;
    }
}
write();//但是这样只会写入最大的文字流数量,进入队列之后就不会再执行了

ws.on("drain", () => {
   write();
});
js 复制代码
复制文件
const fs = require("fs");
const path = require("path");
//方法1
async function method2() {
    const from = path.resolve(__dirname, "./temp/abc.txt");
    const to = path.resolve(__dirname, "./temp/abc2.txt");
    console.time("方式1");
    const content = await fs.promises.readFile(from);
    await fs.promises.writeFile(to, content);
    console.timeEnd("方式1");
    console.log("复制完成");
}
//方法2
async function method2() {
    const from = path.resolve(__dirname, "./temp/abc.txt");
    const to = path.resolve(__dirname, "./temp/abc2.txt");
    console.time("方式2");
    const rs = fs.createReadStream(from);
    const ws = fs.createWriteStream(to);

    rs.on("data", chunk => {
    //读到一部分数据
    const flag = ws.write(chunk);
    if (!flag) {
        //表示下一次写入,会造成背压
        rs.pause(); //暂停读取
      }
  });

    ws.on("drain", () => {
    //可以继续写了
       rs.resume();
    });
    rs.on("close", () => {
    //写完了
    ws.end();//完毕写入流
    console.timeEnd("方式2");
    console.log("复制完成");
  })
}

rs.pipe(ws)

将可读流连接到可写流,返回参数的值,该方法可以解决背压问题(和方法二一样)

相关推荐
coder_leon2 分钟前
Vite打包优化实践:从分包到性能提升
前端
shmily_yyA2 分钟前
【2025】Electron 基础一 (目录及主进程解析)
前端·javascript·electron
吞吞07114 分钟前
浅谈前端性能指标、性能监控、以及搭建性能优化体系
前端
arcsin16 分钟前
雨水-electron项目实战登录
前端·electron·node.js
卑微小文14 分钟前
企业级IP代理安全防护:数据泄露风险的5个关键防御点
前端·后端·算法
SameX16 分钟前
HarmonyOS Next ohpm-repo私有仓库的配置与优化
前端·harmonyos
咪库咪库咪16 分钟前
async await
前端·javascript
华科云商xiao徐18 分钟前
用TypeScript和library needle来创建视频爬虫程序
前端
hahala233319 分钟前
依赖注入(DI)
javascript·node.js
任尔东西南北风22 分钟前
前端请求工具封装
前端·javascript