上一节实现了文件拷贝功能,其中的读和写的操作都耦合在一起了,能不能实现一个方法,可以用一行搞定,这里涉及到流里的 pipe
流
流是有方向的,先读出来再写,node 中实现了流的模块(stream)
文件也想实现流,所以内部文件系统继承了 stream 模块
createReadStream 创建一个可读流(返回一个可读流对象),这个方法默认并不会读取内容:
const fs = require("fs"); const path = require("path"); // createReadStream(path: fs.PathLike, options?: BufferEncoding | ReadStreamOptions | undefined): fs.ReadStream // 内部的实现原理还是:fs.open fs.read fs.close let rs = fs.createReadStream(path.resolve(__dirname, "./name.txt"), { flags: "r", // r 代表读取 encoding: null, // 默认 null,就是 buffer 类型的 mode: 0o666, // 模式:可读可写 autoClose: true, // fs.close start: 0, // 0 - 8 包前又包后 end: 8, highWaterMark: 3 // 每次读取的个数 }); console.log(rs);
为了多个异步方法可以解耦,可以采用发布订阅模式
可读流继承了 events 模块,这里的名字必须要叫 data,源码里写的就是 rs.emit("data")
,如果监听了 data,内部会拼命读取文件的内容,触发对应的回调,默认会直到文件读取完毕
下面新建 name.txt
文件,里面添加:
凯小默的博客
在添加下面的事件监听
const fs = require("fs"); const path = require("path"); let rs = fs.createReadStream(path.resolve(__dirname, "./name.txt"), { flags: "r", // r 代表读取 encoding: null, // 默认 null,就是 buffer 类型的 mode: 0o666, // 模式:可读可写 autoClose: true, // fs.close start: 0, // 0 - 8 包前又包后 end: 8, highWaterMark: 3 // 每次读取的个数 }); let bufferArr = []; // 监听 open(文件流特殊的事件,普通流没有) rs.on("open", (fd) => { console.log("open---->", fd); }); // 监听 data rs.on("data", (data) => { console.log("data---->", data); bufferArr.push(data); // rs.pause 可以让可读流暂停触发 data 事件 rs.pause(); console.log("pause---->暂停"); // 再次触发 data 事件,可以使用 rs.resume setTimeout(() => { console.log("过 2s 再次触发 data 事件"); rs.resume(); }, 2000); }); // 监听 end rs.on("end", () => { console.log("end---->", Buffer.concat(bufferArr).toString()); }); // 监听 error rs.on("error", (err) => { console.log("err---->", err); }); // 监听 close (文件流特殊的事件,普通流没有) rs.on("close", () => { console.log("close---->"); });