是否有一种更简单的方法来复制文件夹及其所有内容,而无需手动执行一系列的fs。readir, fs。readfile, fs。writefile递归?

我只是想知道我是否错过了一个函数,理想情况下是这样工作的:

fs.copy("/path/to/source/folder", "/path/to/destination/folder");

关于这个历史问题。注意fs。Cp和fs。cpSync可以递归复制文件夹,在Node v16+中可用


当前回答

挑选包裹时要小心。有些包(如copy-dir)不支持复制长度超过0X1FFFFFE8个字符(约537 MB)的大文件。

它会抛出一些错误,比如:

buffer.js:630 Uncaught Error:不能创建大于0x1fffffe8字符的字符串

在我的一个项目中,我就经历过类似的事情。最终,我不得不改变我正在使用的包并调整大量代码。我想说,这不是一个很愉快的经历。

如果需要多个源副本和多个目标副本,您可以使用better-copy并编写如下内容:

// Copy from multiple source into a directory
bCopy(['/path/to/your/folder1', '/path/to/some/file.txt'], '/path/to/destination/folder');

甚至:

// Copy from multiple source into multiple destination
bCopy(['/path/to/your/folder1', '/path/to/some/file.txt'], ['/path/to/destination/folder', '/path/to/another/folder']);

其他回答

我尝试了fs-extra和copy-dir来递归地复制文件夹。但我希望它能

正常工作(copy-dir抛出一个不合理的错误) 在过滤器中提供两个参数:filepath和filetype (fs-extra不告诉文件类型) 有从目录到子目录的检查和从目录到文件的检查吗

所以我自己写了:

// Node.js module for Node.js 8.6+
var path = require("path");
var fs = require("fs");

function copyDirSync(src, dest, options) {
  var srcPath = path.resolve(src);
  var destPath = path.resolve(dest);
  if(path.relative(srcPath, destPath).charAt(0) != ".")
    throw new Error("dest path must be out of src path");
  var settings = Object.assign(Object.create(copyDirSync.options), options);
  copyDirSync0(srcPath, destPath, settings);
  function copyDirSync0(srcPath, destPath, settings) {
    var files = fs.readdirSync(srcPath);
    if (!fs.existsSync(destPath)) {
      fs.mkdirSync(destPath);
    }else if(!fs.lstatSync(destPath).isDirectory()) {
      if(settings.overwrite)
        throw new Error(`Cannot overwrite non-directory '${destPath}' with directory '${srcPath}'.`);
      return;
    }
    files.forEach(function(filename) {
      var childSrcPath = path.join(srcPath, filename);
      var childDestPath = path.join(destPath, filename);
      var type = fs.lstatSync(childSrcPath).isDirectory() ? "directory" : "file";
      if(!settings.filter(childSrcPath, type))
        return;
      if (type == "directory") {
        copyDirSync0(childSrcPath, childDestPath, settings);
      } else {
        fs.copyFileSync(childSrcPath, childDestPath, settings.overwrite ? 0 : fs.constants.COPYFILE_EXCL);
        if(!settings.preserveFileDate)
          fs.futimesSync(childDestPath, Date.now(), Date.now());
      }
    });
  }
}
copyDirSync.options = {
  overwrite: true,
  preserveFileDate: true,
  filter: function(filepath, type) {
    return true;
  }
};

还有一个类似的函数mkdirs,它是mkdirp的替代:

function mkdirsSync(dest) {
  var destPath = path.resolve(dest);
  mkdirsSync0(destPath);
  function mkdirsSync0(destPath) {
    var parentPath = path.dirname(destPath);
    if(parentPath == destPath)
      throw new Error(`cannot mkdir ${destPath}, invalid root`);
    if (!fs.existsSync(destPath)) {
      mkdirsSync0(parentPath);
      fs.mkdirSync(destPath);
    }else if(!fs.lstatSync(destPath).isDirectory()) {
      throw new Error(`cannot mkdir ${destPath}, a file already exists there`);
    }
  }
}

挑选包裹时要小心。有些包(如copy-dir)不支持复制长度超过0X1FFFFFE8个字符(约537 MB)的大文件。

它会抛出一些错误,比如:

buffer.js:630 Uncaught Error:不能创建大于0x1fffffe8字符的字符串

在我的一个项目中,我就经历过类似的事情。最终,我不得不改变我正在使用的包并调整大量代码。我想说,这不是一个很愉快的经历。

如果需要多个源副本和多个目标副本,您可以使用better-copy并编写如下内容:

// Copy from multiple source into a directory
bCopy(['/path/to/your/folder1', '/path/to/some/file.txt'], '/path/to/destination/folder');

甚至:

// Copy from multiple source into multiple destination
bCopy(['/path/to/your/folder1', '/path/to/some/file.txt'], ['/path/to/destination/folder', '/path/to/another/folder']);

有一些模块支持复制文件夹及其内容。最流行的是wrench.js:

// Deep-copy an existing directory
wrench.copyDirSyncRecursive('directory_to_copy', 'location_where_copy_should_end_up');

一个替代方案是node-fs-extra:

fs.copy('/tmp/mydir', '/tmp/mynewdir', function (err) {
  if (err) {
    console.error(err);
  } else {
    console.log("success!");
  }
}); // Copies directory, even if it has subdirectories or files

这在Node.js 10中非常简单:

const Path = require('path');
const FSP = require('fs').promises;

async function copyDir(src,dest) {
    const entries = await FSP.readdir(src, {withFileTypes: true});
    await FSP.mkdir(dest);
    for(let entry of entries) {
        const srcPath = Path.join(src, entry.name);
        const destPath = Path.join(dest, entry.name);
        if(entry.isDirectory()) {
            await copyDir(srcPath, destPath);
        } else {
            await FSP.copyFile(srcPath, destPath);
        }
    }
}

这里假设dest不存在。

使用 shelljs

npm i -D shelljs

const bash = require('shelljs');
bash.cp("-rf", "/path/to/source/folder", "/path/to/destination/folder");