nodejs 中有多种复制文件的方式,我们一起来看看。
1. copyFile #
copyFile()方法的操作最简单,可以直接将文件复制到目标目录中。
fs.copyFile('./a.txt', './dist/b.txt');
异步地将 src 复制到 dest。 默认情况下,如果 dest 已经存在,则会被覆盖。 除了可能的异常之外,没有给回调函数提供任何参数。 Node.js 不保证复制操作的原子性。 如果在打开目标文件进行写入后发生错误,Node.js 将尝试删除目标文件。
但这个方法有一个缺点:目标目录一定要存在(它不会自动创建目录),若不存在时则会抛出异常。因此在使用 copyFile()方法时,一定要确保目录肯定存在,若不存在的话,则需要使用fs.mkdir()
或fs.mkdirSync()
来创建目录。
而且,copyFile()不能复制目录。
2. readFile 和 writeFile #
读取 src 文件的内容,然后再写入到目标文件中。
这种方式适合于,在复制过程中,需要修改内容的,再写入目标文件。
fs.readFile('./a.txt', { encoding: 'utf8' }, (err, data) => {
if (err) {
console.error(err);
return;
}
data = data.replace(/hello/gi, 'world');
fs.writeFile('./b.txt', data, (err) => {
if (err) {
console.error(err);
}
});
});
缺点与上面的 copyFile()一样,writeFile()只能在已存在的目录中才能写入文件,readFile()是用来读取文件内容的,因此也无法复制目录。
好处就是在复制过程中,可以修改内容。
3. createReadStream 和 createWriteStream #
readFile 和 writeFile 是整块的操作数据,若文件比较大,则会系统资源造成压力。而 createReadStream 和 createWriteStream 是采用流的方式来操作数据。
fs.createReadStream('./a.txt').pipe(fs.createWriteStream(`./b.txt`));
4. cp #
nodejs 从 16.7.0 版本开始,新加入了一个fs.cp()方法,可以将整个目录结构从 src 异步地复制到 dest,包括子目录和文件。
该方法既可以复制某一个文件,也可以复制一个目录。当需要复制目录时,需要将配置中的recursive
属性设置为 true。
复制文件:
// 复制文件
fs.cp('./a.txt', './aa/b.txt', (err) => {
if (err) {
console.error(err);
}
});
复制整个目录,包括子目录:
// 复制目录
fs.cp('./aa', './bb', { recursive: true }, (err) => {
if (err) {
console.error(err);
}
});
可以看到,该方法比前面的要好使很多:
- 不用再确保 dest 目录一定存在,若 dest 目录不存在,则会自动创建(无论几级目录);
- 可以完整地复制整个文件夹里的文件,包括子目录,不用再递归地单独进行复制;
唯一要做的,就是确认好 nodejs 版本!
若您的 nodejs 版本比较低,但又想复制文件夹中的所有文件,怎么办呢?除了可以下一节的 linux 原生 cp 命令,我们还可以用递归的方式来,来复制有的文件:
/**
* 复制文件夹到目标文件夹
* @param {string} src 源目录
* @param {string} dest 目标目录
* @param {function} callback 回调
*/
const copyDir = (src, dest, callback) => {
const copy = (copySrc, copyDest) => {
fs.readdir(copySrc, (err, list) => {
if (err) {
callback(err);
return;
}
list.forEach((item) => {
const ss = path.resolve(copySrc, item);
fs.stat(ss, (err, stat) => {
if (err) {
callback(err);
} else {
const curSrc = path.resolve(copySrc, item);
const curDest = path.resolve(copyDest, item);
if (stat.isFile()) {
// 文件,直接复制
fs.createReadStream(curSrc).pipe(fs.createWriteStream(curDest));
} else if (stat.isDirectory()) {
// 目录,进行递归
fs.mkdirSync(curDest, { recursive: true });
copy(curSrc, curDest);
}
}
});
});
});
};
fs.access(dest, (err) => {
if (err) {
// 若目标目录不存在,则创建
fs.mkdirSync(dest, { recursive: true });
}
copy(src, dest);
});
};
使用方式:
copyDir('./aa', './abc/ddd');
5. linux 中的 cp 命令 #
我们可以使用 child_process 中的exec
或spawn
等来执行 linux 中的原生命令。而linux 中的 cp 命令就是用来复制文件或者目录的。
const { exec, spawn } = require('child_process');
exec('cp ./aa/a.txt ./bb/b.txt'); // 复制文件时,需要确保目标目录存在
exec('cp -r ./aa ./bb/cc/dd'); // 复制文件夹,目标目录可以自动创建
spawn('cp', ['-r', './aa', './bb/cc/dd']);