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常见的方法:
