Logo Vincent
返回文章列表

Node.js-开发实践:使用健壮的FS

Node.js
Node.js-开发实践:使用健壮的FS

【前言】

fs模块是nodejs中最常见的模块,

可是fs的使用经常会有各种意想不到的坑。

【高性能FS】

其中之一是没有使用高性能的fs,

导致在electron应用中造成卡顿,

fs模块有3种使用方式,

callback方式

1. 书写会导致回调地狱

2. 体现nodejs事件驱动,非阻塞io

3. 性能最好

promise方式

1. 书写需要配合async / await使用

2. 也体现事件驱动,非阻塞io

3. 性能和callback很接近,稍微有损耗

sync方式

1. 书写最简单, 也不需要async / await

2. 阻塞性使用

3. 性能极差,谨慎使用

所以高性能FS推荐使用promise方式,

详见: https://blog.insistime.com/nodejs-fs

【mkdir】

mkdir方法用来创建文件夹,代码如下

const { mkdir } = require('node:fs/promises');

async function test() {
  const dir = './1/2';
  const res = await mkdir(dir);
  console.log(res);
}
test();

但是这样用会报错,如下

因为1文件夹不存在,所以无法创建2文件夹

解决方案:添加recursive属性

recursive属性可以递归创建不存在的文件夹

const { mkdir } = require('node:fs/promises');

async function test() {
  const dir = './1/2';
  const res = await mkdir(dir, { recursive: true });
  console.log(res);
}
test();

【copyFile】

copyFile方法用来复制文件,代码如下

const { copyFile } = require('node:fs/promises');

async function test() {
  await copyFile('mkdir.js', './3/4/mkdir.js');
}
test();

同样也会报错,如下

因为3文件夹,4文件夹都不存在

解决方案:复制文件前先创建目标文件夹

// path
const path = require('node:path');

// fs
const { mkdir, copyFile } = require('node:fs/promises');

async function test() {
  const src = 'mkdir.js';
  const dest = './3/4/mkdir.js';

  await mkdir(path.dirname(dest), { recursive: true });
  await copyFile('mkdir.js', './3/4/mkdir.js');
}
test();

【cp】

cp方法用来复制文件夹,代码如下:

const { cp } = require('node:fs/promises');

async function test() {
  const src = './3/4';
  const dest = './33/44';
  await cp(src, dest);
}
test();

同样报错,如下

因为src是文件夹

解决方案:使用recursive属性

和mkdir类似,使用recursive属性即可

const { cp } = require('node:fs/promises');

async function test() {
  const src = './3/4';
  const dest = './33/44';
  await cp(src, dest, { recursive: true });
}
test();

【rm】

rm方法用来删除文件或文件夹,代码如下

const { rm } = require('node:fs/promises');

async function test() {
  const src = '/not/exists/';
  await rm(src);
}
test();

直接使用会报错,如下:

解决方案:删除前先判断path是否存在

const { access, rm } = require('node:fs/promises');

async function test() {
  const src = '/not/exists/';
  if (!(await isExists(src))) {
    console.log(`${src} not exists`);
    return;
  }

  await rm(src);
}
test();

async function isExists(path) {
  try {
    await access(path);
    return true;
  } catch (error) {
    return false;
  }
}

如果要删除的是文件夹,依然会失败,

解决方案:使用recursive属性

const { access, rm } = require('node:fs/promises');

async function test() {
  const src = './33/44';
  if (!(await isExists(src))) {
    console.log(`${src} not exists`);
    return;
  }

  await rm(src, { recursive: true });
}
test();

async function isExists(path) {
  try {
    await access(path);
    return true;
  } catch (error) {
    return false;
  }
}

【rename】

rename方法用来重命名路径,代码如下:

const { rename } = require('node:fs/promises');

async function test() {
  const src = './3/4';
  const dest = './333/333';
  await rename(src, dest);
}
test();

依然报错,如下:

解决方案:判断src是否存在并生成dest的父文件夹

const { access, mkdir, rename } = require('node:fs/promises');

async function test() {
  const src = './3';
  const dest = './333/333';

  if (!(await isExists(src))) {
    console.log(`${src} not exists`);
    return;
  }

  await mkdir(dest, { recursive: true });
  await rename(src, dest);
}
test();

async function isExists(path) {
  try {
    await access(path);
    return true;
  } catch (error) {
    return false;
  }
}

【fs-extra】

总结下来有几类问题

1.操作需要递归

例如mkdir一个/3/4/5

2.操作需要判断路径是否存在

例如rm一个/not/exists

3.操作需要判断是文件还是文件夹

实践中远远不止这些异常,

这里推荐一个npm包: https://www.npmjs.com/package/fs-extra

简单来说是fs的一个超集,

支持fs的相关方法,

又封装了一些常用的方法,

包括上述代码健壮性方面的封装

fs-extra常见的方法:

© 2026 Vincent. 保留所有权利。