Wenzi

nodejs 中复制文件和文件夹的多种方式

蚊子前端博客
发布于 2022/05/27 16:21
nodejs 中有多种复制文件的方式,我们一起来看看。

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);
  }
});

可以看到,该方法比前面的要好使很多:

  1. 不用再确保 dest 目录一定存在,若 dest 目录不存在,则会自动创建(无论几级目录);
  2. 可以完整地复制整个文件夹里的文件,包括子目录,不用再递归地单独进行复制;

唯一要做的,就是确认好 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 中的execspawn等来执行 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']);
标签:nodejsfs
阅读(606)
Simple Empty
No data