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 的事件队列中。