文章目录
- 背景
- 读
- 写
- 创建
- 复制
- 移动(重命名)
- 是否存在
- 删除
- 示例
- 1、文件内容替换
- 2、文件夹内的所有文件内容替换
- 封装
背景
我们日常工作中,想要对前端做一些自动化操作的时候,免不了使用 node 的文件读写操作,今天来总结一下 fs 模块常用的操作。
在实际工作中,为了工程化,最好将 fs 模块进行封装,比如捕获一下错误等等,这样就不用每次都 try catch 了。可以看文末的封装
读
读文件:fs.readFileSync
// 一般对于路径相关的要用__dirname等操作拼接一下,如果直接写相对路径可能会有问题,比如:index.js中写了相对路径,那么执行node test/index.js 和 cd test && node index.js是不一样的。
const sourcePath = path.resolve(__dirname, './index.js')
// 这里拿到的content就是文件内容的字符串
const content = fs.readFileSync(sourcePath, 'utf-8')
读文件夹:fs.readFileSync
const sourcePath = path.resolve(__dirname, './')
const content = fs.readdirSync(sourcePath, 'utf-8')
// 返回的是文件夹下的文件数组:[ 'index.js', 'tool.js' ]
写
写入文件,若文件不存在则创建文件
// sourcePath:源文件路径
// outputContent:要写入的内容
fs.writeFileSync(sourcePath, outputContent, 'utf-8');
追加到文件尾部,另起一行
// sourcePath:源文件路径
// outputContent:要写入的内容
fs.appendFileSync(sourcePath, '追加的文字');
创建
创建文件
见上面写入文件
创建目录
// 创建 test 目录
const sourcePath = path.resolve(__dirname, './test')
// 创建多个目录
const sourcePath = path.resolve(__dirname, './test/test1')
fs.mkdirSync(sourcePath);
复制
复制文件
const sourcePath = path.resolve(__dirname, './index.js')
const outputPath = path.resolve(__dirname, './test.js')
fs.copyFileSync(sourcePath, outputPath);
复制目录
1、第三方库
// 使用第三方模块
var fs = require("fs-extra");
fs.copySync("./source/myDirectory", "./target/myDirectory")
2、原生方式
nodejs 从 16.7.0 版本开始,新加入了一个fs.cp()方法,可以复制目录(不管目标目录是否存在都可自动创建)。当需要复制目录时,需要将配置中的recursive属性设置为 true。
const sourcePath = path.resolve(__dirname, './source/')
const outputPath = path.resolve(__dirname, './target/')
const res = fs.cpSync(sourcePath, outputPath, { recursive: true });
3、自己写递归复制
见底部封装
移动(重命名)
const sourcePath = path.resolve(__dirname, './index.js')
const outputPath = path.resolve(__dirname, './test.js')
const res = fs.renameSync(sourcePath, outputPath);
是否存在
是否是文件
const sourcePath = path.resolve(__dirname, './index.js')
const stats = fs.statSync(sourcePath);
const isFile = stats.isFile()
是否是目录
const sourcePath = path.resolve(__dirname, './index.js')
const stats = fs.statSync(sourcePath);
const isDirectory = stats.isDirectory()
删除
删除文件
const sourcePath = path.resolve(__dirname, './index.js')
const res = fs.unlinkSync(sourcePath);
删除目录
必须是空目录才能删除,如果里面有文件此命令报错
const sourcePath = path.resolve(__dirname, './test')
const res = fs.rmdirSync(sourcePath);
示例
1、文件内容替换
将 index.js 文件中的 aaa 替换为 hhh,在 tool.js 写入以下代码:
const fs = require('fs')
const path = require('path')
const sourcePath = path.resolve(__dirname, './index.js')
const content = fs.readFileSync(sourcePath, 'utf-8')
const outputContent = content.replaceAll(/aaa/g, "hhh");
fs.writeFileSync(sourcePath, outputContent, 'utf-8');
写完后执行 node tool.js
,这时 aaa 已经变为 hhh 了
2、文件夹内的所有文件内容替换
思路:读取文件夹并遍历,如果是文件则读取替换,如果是文件夹则继续递归遍历。
方案:使用 shell 的文件替换,可以看 这篇,使用 node 开启一个子进程执行 shell 脚本。
const process = require("child_process");
process.exec('sh xxx.sh', (error, stdout, stderr) => {
if (!error) {
// 成功
} else {
// 失败
}
});
封装
import fs from 'fs';
import path from 'path';
import globPkg from 'glob';
import mkdirp from 'mkdirp';
export const copyFile = (source, target) =>
new Promise((resolve, reject) => {
let cbCalled = false;
function done(err) {
if (!cbCalled) {
cbCalled = true;
if (err) {
reject(err);
} else {
resolve(true);
}
}
}
const rd = fs.createReadStream(source);
rd.on('error', (err) => done(err));
const wr = fs.createWriteStream(target);
wr.on('error', (err) => done(err));
wr.on('close', (err) => done(err));
rd.pipe(wr);
});
export const readFile = (file) =>
new Promise((resolve, reject) => {
fs.readFile(file, 'utf8', (err, data) =>
err ? reject(err) : resolve(data)
);
});
export const writeFile = (file, contents) =>
new Promise((resolve, reject) => {
fs.writeFile(file, contents, 'utf8', (err) =>
err ? reject(err) : resolve(true)
);
});
export const glob = (pattern: string): Promise<string[]> =>
new Promise((resolve, reject) => {
globPkg(pattern, (err, val) => (err ? reject(err) : resolve(val)));
});
export const fileExist = async (pattern) => {
const fileList = await glob(pattern);
return fileList.length !== 0;
};
export const makeDir = async (name) => {
await mkdirp(name);
};
export const readDir = (pattern, options): Promise<string[]> =>
new Promise((resolve, reject) =>
globPkg(pattern, options, (err, result) =>
err ? reject(err) : resolve(result)
)
);
export const copyDir = async (source, target) => {
const dirs = await readDir('**/*.*', {
cwd: source,
nosort: true,
dot: true
});
await Promise.all(
dirs.map(async (dir) => {
const from = path.resolve(source, dir);
const to = path.resolve(target, dir);
await makeDir(path.dirname(to));
await copyFile(from, to);
})
);
};
export const renameFile = (source, target) =>
new Promise((resolve, reject) => {
fs.rename(source, target, (err) => (err ? reject(err) : resolve(true)));
});
export const rmFile = async (source) =>
new Promise((resolve, reject) => {
fs.unlink(source, (err) => {
if (err) {
reject(err);
} else {
resolve(true);
}
});
});
export default {
readFile,
writeFile,
copyFile,
glob,
fileExist,
makeDir,
renameFile,
rmFile
};