feng xiaohan

fs

Nodejs 核心 API。提供与文件系统交互功能,包括读写、修改文件权限,创建目录等操作。

读取文件 - readFile

readFile - 异步

可指定文件编码格式,不会阻塞下面代码。

fs.readFile(
  "./util.md",
  {
    encoding: "utf-8",
    flag: "r",
  },
  (err, data) => {
    if (err) {
      return;
    }
    console.log(data);
  }
);

readFileSync - 同步

会阻塞下面代码,返回一个二进制流,可通过toString()转换。

const resulet = fs.readFileSync("./test.js");
console.log(resulet.toString("utf-8"));

promise

promise 版本。

const fs2 = require("node:fs/promises");
fs2
  .readFile("./test.js")
  .then((resulet) => {
    console.log(resulet.toString("utf-8"));
  })
  .catch((err) => {});

可读流 - createReadStream

可以将文件以二进制流的形式读取,通过监听该文件流对应事件来获取文件数据。

适用于处理大文件。

const readSreanm = fs.createReadStream("./test.js");
readSreanm.on("data", (chunk) => {
  console.log(chunk.toString());
});
readSreanm.on("end", () => {
  console.log("end");
});

创建文件

创建文件夹。

fs.mkdirSync("./ff"); // 创建一个文件夹
// 创建多层文件夹
fs.mkdirSync("./ff/f1/f2", {
  recursive: true,
});

删除文件

删除文件夹。

// 删除文件夹(如果该文件夹内还有其他文件会报错)
fs.rmSync("./ff");
// 递归删除文件夹底下的的所有子目录
fs.rmSync("./ff", {
  recursive: true,
});

重命名文件

fs.renameSync("./index.txt", "./index2.txt");

监听文件变化

文件有修改时触发。

大部分构建工具的热更新原理。

fs.watch("./index.txt", (event, filename) => {
  console.log(event, filename);
});

写入文件

fs.writeFileSync("./index.txt", "write cnotent", {
  flag: "a", // 追加内容在文件中,如果没有该文件则覆盖,不然默认覆盖
});

fs.appendFileSync("./index.txt", "js");
  • r:以读取模式打开文件。如果文件不存在,则抛出异常。
  • r+:以读写模式打开文件。如果文件不存在,则抛出异常。
  • w:以写入模式打开文件。如果文件不存在,则创建文件;如果文件存在,则截断文件。
  • w+:以读写模式打开文件。如果文件不存在,则创建文件;如果文件存在,则截断文件。
  • a:以追加模式打开文件。如果文件不存在,则创建文件。
  • a+:以读和追加模式打开文件。如果文件不存在,则创建文件

可写流

适用于大量的数据分批插入

const writeStream = fs.createWriteStream("./index.txt");
const verse = ["ddd", "dddd", "dddddd", "dddddddd"];
verse.forEach((item) => {
  writeStream.write(item + "\n");
});
writeStream.end();

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

软硬链接

硬链接

链接双方共享一个内存地址。用于共享文件,备份文件。(引用类型)

fs.linkSync("./index.txt", "./index2.txt"); // 原始地址,硬链接之后地址
  • 硬链接会创建一个新的文件,与原始地址文件同步
  • 原始地址文件删除并不影响硬链接文件

软链接(符号链接)

注意:需开启管理员权限

链接文件相当于一个原始文件的快捷方式

fs.symlinkSync("./index.txt", "./index3.txt");

应用

pnpm 的底层原理就是通过软硬链接实现的。

源码分析

通过 libuv(c++)的对uv_fs_t的封装,也就是将 fs 的参数透传给 libuv 层。

// - loop:事件循环对象,用于处理异步操作
// - req:文件系统请求对象,用于保存操作的状态和结果
// - path:要创建的目录的路径
// - mode:目标权限模式
// - cb:操作完成后的回调函数
int uv_fs_mkdir(uv_loop_t* loop,
                uv_fs_t* req,
                const char* path,
                int mode,
                uv_fs_cb cb) {
  INIT(MKDIR);
  PATH;
  req->mode = mode;
  if (cb != NULL)
    if (uv__iou_fs_mkdir(loop, req))
      return 0;
  POST;
}

与事件循环的关系

fs 的 IO 操作都是由 libuv 完成的,它会等到本轮事件循环结束,并且完成任务之后才会将其推入 v8 的事件队列中。