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)

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

相关推荐
满怀101521 分钟前
【Vue 3全栈实战】从响应式原理到企业级架构设计
前端·javascript·vue.js·vue
luckywuxn30 分钟前
使用gitbook 工具编写接口文档或博客
前端
梅子酱~1 小时前
Vue 学习随笔系列二十三 -- el-date-picker 组件
前端·vue.js·学习
伟笑1 小时前
elementUI 循环出来的表单,怎么做表单校验?
前端·javascript·elementui
辣辣y1 小时前
React中useMemo和useCallback的作用:
前端·react
Alice-YUE1 小时前
【HTML5学习笔记1】html标签(上)
前端·笔记·学习·html·html5
Alice-YUE1 小时前
【HTML5学习笔记2】html标签(下)
前端·笔记·html·html5
确实菜,真的爱1 小时前
electron进程通信
前端·javascript·electron
!win !3 小时前
uni-app小程序登录后…
前端·uni-app
Nightne3 小时前
CSS图片垂直居中问题解决方案
前端·css