NodeJs 中复制(拷贝)文件或文件夹的多种方式
# 1. copyFile
copyFile()方法的操作最简单,可以直接将文件复制到目标目录中。
fs.copyFile('./a.txt', './dist/b.txt');
::: info 异步地将 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);
}
});
});
2
3
4
5
6
7
8
9
10
11
12
缺点与上面的 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);
}
});
2
3
4
5
6
复制整个目录,包括子目录:
// 复制目录
fs.cp('./aa', './bb', { recursive: true }, (err) => {
if (err) {
console.error(err);
}
});
2
3
4
5
6
可以看到,该方法比前面的要好使很多:
不用再确保 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');
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
或者
const fs = require('fs')
const path = require('path')
function copyFiles(srcDir, destDir) {
//读取源文件地址的所有文件和文件格式
fs.readdir(srcDir, { withFileTypes: true }, (err, files) => {
if (!err) {
for (let file of files) {
//判断是否为文件夹类型
if (file.isDirectory()) {
const srcFile = path.resolve(srcDir, file.name)
const destFile = path.resolve(destDir, file.name)
//同步创建文件夹
fs.mkdirSync(destFile, err => {
console.log(err);
})
copyFiles(srcFile, destFile)
} else {
const srcFile1 = path.resolve(srcDir, file.name)
const destFile1 = path.resolve(destDir, file.name)
if (fs.existsSync(destFile1)) {
console.log("已经存在相同文件,无需复制");
continue
}
fs.copyFileSync(srcFile1, destFile1)
console.log("复制成功");
}
}
}
})
}
//使用方式:
const srcDir = process.argv[2] //源文件路径
const destDir = process.argv[3] //目标文件路径
copyFiles(srcDir, destDir)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 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']);
2
3
4
5
6
- 01
- linux 在没有 sudo 权限下安装 Ollama 框架12-23
- 02
- Express 与 vue3 使用 sse 实现消息推送(长连接)12-20