源本科技 | 码上会

Node.js 内置模块 fs

2026/04/09
42
0

引言

Node.js 的内置模块 fs(File System,文件系统)提供了操作系统文件的核心能力。通过 fs 模块,你可以完成文件的读写、创建、删除、重命名,以及目录的创建、遍历、删除等操作。 该模块内置在 Node.js 中,无需额外安装,同时支持异步回调、同步阻塞、Promise 三种调用方式,是 Node.js 服务端开发中处理文件的核心模块。


快速开始

node 命令可以在终端中直接执行 JavaScript 文件。

  • 创建一个 JavaScript 文件,如 hello-world.js,编写代码:

console.log('Hello Node.js!')
  • 打开终端,进入文件所在目录,执行命令:

node hello-world.js

执行成功后,终端会输出对应的打印内容。


前置配置

  • 在项目根目录的 package.json 中添加配置,启用 ES Module 规范:

{
  "type": "module"
}
  • 核心固定代码:ES Module 中无默认 __dirname,所有文件操作必须先定义(全局复用):

import { fileURLToPath } from 'url';
import { dirname } from 'path';

// 获取当前文件的绝对路径
const __filename = fileURLToPath(import.meta.url);
// 获取当前文件所在目录的绝对路径
const __dirname = dirname(__filename);

模块导入

// 导入 fs 文件系统模块
import fs from 'fs';
// 导入 path 路径模块(用于安全拼接路径)
import path from 'path';
// 固定:定义 __dirname
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

文件路径安全处理

直接拼接路径容易出现跨系统错误(Windows \ / Mac/Linux /),必须使用 path.join() 拼接

import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// 跨系统兼容的安全路径
const filePath = path.join(__dirname, 'files', 'test.txt');

常用方法

方法

说明

fs.readFile()

异步读取文件内容

fs.readFileSync()

同步读取文件内容

fs.writeFile()

异步写入文件(覆盖 / 追加)

fs.mkdir()

创建目录

fs.readdir()

读取目录内容

fs.rename()

重命名 / 移动文件 / 目录

fs.unlink()

删除文件

fs.rmdir()

删除空目录


文件读取

异步读取

import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const filePath = path.join(__dirname, 'files', 'test.txt');

// 异步读取:错误优先回调
fs.readFile(filePath, 'utf8', (err, data) => {
  if (err) {
    console.error('文件读取失败:', err);
    return;
  }
  console.log('文件内容:', data);
});

同步读取

import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const filePath = path.join(__dirname, 'files', 'test.txt');

// 同步读取:try/catch 捕获异常
try {
  const data = fs.readFileSync(filePath, 'utf8');
  console.log('文件内容:', data);
} catch (err) {
  console.error('文件读取失败:', err);
}

文件写入

覆盖写入

import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const filePath = path.join(__dirname, 'files', 'test1.txt');

// 覆盖写入文件
fs.writeFile(filePath, 'Hello my first node.js', 'utf8', err => {
  if (err) {
    console.error('文件写入失败:', err);
  } else {
    console.log('文件写入成功');
  }
});

追加写入

// 基于上方代码,追加内容
fs.writeFile(filePath, '\n追加的内容', { encoding: 'utf8', flag: 'a' }, err => {
  if (!err) console.log('追加成功');
});

目录与文件操作

import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const dirPath = path.join(__dirname, 'my-folder');

// 1. 递归创建多级目录
fs.mkdir(dirPath, { recursive: true }, err => {
  if (!err) console.log('目录创建成功');
});

// 2. 读取目录内容
fs.readdir(__dirname, (err, files) => {
  console.log('当前目录文件:', files);
});

// 3. 重命名文件/目录
fs.rename(dirPath, path.join(__dirname, 'new-folder'), () => {});

// 4. 删除文件
fs.unlink(path.join(__dirname, 'test.txt'), () => {});

// 5. 删除空目录
fs.rmdir(dirPath, () => {});

箭头函数

ES6 语法,简化 fs 回调函数代码,是文件操作的标准写法。

基础语法

// 无参数
const func1 = () => {}
// 单个参数(可省略括号)
const func2 = param => {}
// 多个参数
const func3 = (param1, param2) => {}
// 单行返回值(省略 return 和大括号)
const add = (a, b) => a + b

核心特性

  • 语法简洁:大幅缩短回调函数代码

  • 无独立 this:继承父作用域的 this

  • 不能用作构造函数:无法使用 new 调用

  • arguments 对象


同步与异步

fs 模块的核心设计:异步非阻塞(Node.js 精髓),同步方法仅适合简单场景。

类型

优点

缺点

使用场景

异步回调

不阻塞程序,高性能

易产生回调地狱

生产环境、服务端开发

同步阻塞

代码简单,易调试

阻塞程序,性能差

本地脚本、测试代码


补充:IO 模型核心概念

文件操作的本质是 IO(输入 / 输出),根据阻塞特性和实现方式,分为三大经典模型,直接对应 Node.js fs 模块的不同用法:

1. BIO(同步并阻塞)

  • 定义:发起 IO 操作后,程序完全阻塞等待,直到 IO 完成才能执行后续代码

  • 对应 Node.js 方法fs.readFileSync / fs.writeFileSync同步方法

  • 特点:单线程下会卡住整个程序,效率低

  • 场景:简单脚本、初始化配置、测试代码

2. NIO(同步非阻塞)

  • 定义:发起 IO 操作后,程序不阻塞,可以继续执行其他任务;轮询 / 事件监听 IO 完成状态

  • 对应 Node.js 方法fs.readFile / fs.writeFile异步回调方法

  • 特点:基于事件循环,高性能;回调嵌套过多会产生「回调地狱」

  • 场景:服务端常规文件操作

3. AIO(异步非阻塞)

  • 定义:发起 IO 操作后,程序无需等待、无需轮询;操作系统完成 IO 后主动通知程序

  • 对应 Node.js 方法fs/promises + async/await

  • 特点:最优雅的异步模型,无阻塞、无回调地狱、代码可读性极高

  • 场景:生产环境、大型项目(官方最优方案

核心区别

模型

阻塞状态

通知方式

Node.js 对应

易用性

BIO

阻塞

执行完成自动继续

同步 fs

NIO

非阻塞

回调函数

异步回调 fs

AIO

非阻塞

系统主动通知

Promise fs/async-await

最高