惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Check Point Blog
IT之家
IT之家
V
Visual Studio Blog
The Cloudflare Blog
博客园 - 司徒正美
Jina AI
Jina AI
博客园_首页
阮一峰的网络日志
阮一峰的网络日志
美团技术团队
S
SegmentFault 最新的问题
博客园 - 聂微东
人人都是产品经理
人人都是产品经理
T
Tailwind CSS Blog
罗磊的独立博客
酷 壳 – CoolShell
酷 壳 – CoolShell
量子位
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Hugging Face - Blog
Hugging Face - Blog
博客园 - 【当耐特】
博客园 - 三生石上(FineUI控件)
爱范儿
爱范儿
博客园 - Franky
Last Week in AI
Last Week in AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知

蚊子的前端博客

微说 | 有的人觉得只要不考XX,一定能考好!-蚊子的前端博客 微说 | 春天来了-蚊子的前端博客 明天和意外不知道哪个先来-蚊子的前端博客 微说 | 既然错过了路口,就及时止损,重新规划路线上路-蚊子的前端博客 微说 | 2025年的出生人口数是792万-蚊子的前端博客 微说 | 工作年终总结,让写对接的接口的数量?-蚊子的前端博客 微说 | 温家宝:没有政治体制改革的成功 经济体制改革不可能进行到底-蚊子的前端博客 微说 | 违法犯罪了该不该被禁言?-蚊子的前端博客 微说 | 不明白为什么在推荐去俄罗斯旅游-蚊子的前端博客 微说 | 易中天论骗子-蚊子的前端博客 微说 | 一场大风吹散了秋天-蚊子的前端博客 微说 | 既要、又要、还要、更要!-蚊子的前端博客 又是一年的国庆雨季-蚊子的前端博客 微说 | 预估下2025年的出生人口数据-蚊子的前端博客 微说 | 可惜了我那些小时候的书本-蚊子的前端博客 微说 | 牛马有的是,驴不够了!-蚊子的前端博客 微说 | 能否有一条非户口也能高考的路-蚊子的前端博客 微说 | 小聊中医-蚊子的前端博客 微说 | 将要制作的一款新产品-蚊子的前端博客 微说 | 做人要有信-蚊子的前端博客 微说 | 好一个正义联盟-蚊子的前端博客 微说 | 都是见过吃过的主儿-蚊子的前端博客 微说 | 追求8小时工作制有错吗?-蚊子的前端博客 微说 | 如果尖锐的批评完全消失-蚊子的前端博客 微说 | 很好!-蚊子的前端博客 微说 | 封禁用户可以,但要告知具体原因-蚊子的前端博客 微说 | 面朝大海,春暖花开-蚊子的前端博客 微说 | 程序员的悲哀是什么?-蚊子的前端博客 微说 | 2025年出生人口的预测-蚊子的前端博客 前端在 LiveKit 中如何获取所有的参与者-蚊子的前端博客
nodejs 中复制文件和文件夹的多种方式-蚊子的前端博客
author · 2022-05-27 · via 蚊子的前端博客

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']);