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

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

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

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


当前回答

这可能是一个可能的解决方案使用异步生成器函数和迭代等待循环。这个解决方案包括过滤掉一些目录的可能性,将它们作为可选的第三个数组参数传递。

import path from 'path';
import { readdir, copy } from 'fs-extra';

async function* getFilesRecursive(srcDir: string, excludedDir?: PathLike[]): AsyncGenerator<string> {
  const directoryEntries: Dirent[] = await readdir(srcDir, { withFileTypes: true });
  if (!directoryEntries.length) yield srcDir; // If the directory is empty, return the directory path.
  for (const entry of directoryEntries) {
    const fileName = entry.name;
      const sourcePath = resolvePath(`${srcDir}/${fileName}`);
      if (entry.isDirectory()) {
        if (!excludedDir?.includes(sourcePath)) {
          yield* getFilesRecursive(sourcePath, excludedDir);
        }
      } else {
        yield sourcePath;
      }
  }
}

然后:

for await (const filePath of getFilesRecursive(path, ['dir1', 'dir2'])) {
   await copy(filePath, filePath.replace(path, path2));
}

其他回答

对于Linux/Unix操作系统,可以使用shell语法

const shell = require('child_process').execSync;

const src = `/path/src`;
const dist = `/path/dist`;

shell(`mkdir -p ${dist}`);
shell(`cp -r ${src}/* ${dist}`);

就是这样!

这是我个人的做法:

function copyFolderSync(from, to) {
    fs.mkdirSync(to);
    fs.readdirSync(from).forEach(element => {
        if (fs.lstatSync(path.join(from, element)).isFile()) {
            fs.copyFileSync(path.join(from, element), path.join(to, element));
        } else {
            copyFolderSync(path.join(from, element), path.join(to, element));
        }
    });
}

它适用于文件夹和文件。

我尝试了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`);
    }
  }
}

是的,ncp很酷…

你可能想要/应该承诺它的功能,让它超级酷。当你这样做的时候,把它添加到一个工具文件中以重复使用它。

下面是一个工作版本,它是异步的,并使用承诺。


文件index.js

const {copyFolder} = require('./tools/');

return copyFolder(
    yourSourcePath,
    yourDestinationPath
)
.then(() => {
    console.log('-> Backup completed.')
}) .catch((err) => {
    console.log("-> [ERR] Could not copy the folder: ", err);
})

文件tools.js

const ncp = require("ncp");

/**
 * Promise Version of ncp.ncp()
 *
 * This function promisifies ncp.ncp().
 * We take the asynchronous function ncp.ncp() with
 * callback semantics and derive from it a new function with
 * promise semantics.
 */
ncp.ncpAsync = function (sourcePath, destinationPath) {
  return new Promise(function (resolve, reject) {
      try {
          ncp.ncp(sourcePath, destinationPath, function(err){
              if (err) reject(err); else resolve();
          });
      } catch (err) {
          reject(err);
      }
  });
};

/**
 * Utility function to copy folders asynchronously using
 * the Promise returned by ncp.ncp().
 */
const copyFolder = (sourcePath, destinationPath) => {
    return ncp.ncpAsync(sourcePath, destinationPath, function (err) {
        if (err) {
            return console.error(err);
        }
    });
}
module.exports.copyFolder = copyFolder;

从Node v16.7.0开始,可以使用fs。Cp或fs。cpSync函数。

fs.cp(src, dest, {recursive: true});

电流稳定性(在节点v18.7.0中)是实验性的。