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

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

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

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


当前回答

看起来ncp和扳手都不再维护了。可能最好的选择是使用fs-extra

扳手的开发人员指导用户使用fs-extra,因为他已经弃用了他的库

copySync和moveSync都将复制和移动文件夹,即使他们有文件或子文件夹,你可以很容易地移动或复制文件使用它

const fse = require('fs-extra');

const srcDir = `path/to/file`;
const destDir = `path/to/destination/directory`;
                                 
// To copy a folder or file, select overwrite accordingly
try {
  fs.copySync(srcDir, destDir, { overwrite: true|false })
  console.log('success!')
} catch (err) {
  console.error(err)
}

OR

// To Move a folder or file, select overwrite accordingly
try {
  fs.moveSync(srcDir, destDir, { overwrite: true|false })
  console.log('success!')
} catch (err) {
  console.error(err)
}

其他回答

有一些模块支持复制文件夹及其内容。最流行的是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 v16.7.0开始:

import { cp } from 'fs/promises';
await cp(
  new URL('../path/to/src/', import.meta.url),
  new URL('../path/to/dest/', import.meta.url), {
    recursive: true,
  }
);

注意使用递归:true。这可以防止ERR_FS_EISDIR错误。

阅读更多关于节点文件系统的文档

内联版本

node -e "const fs=require('fs');const p=require('path');function copy(src, dest) {if (!fs.existsSync(src)) {return;} if (fs.statSync(src).isFile()) {fs.copyFileSync(src, dest);}else{fs.mkdirSync(dest, {recursive: true});fs.readdirSync(src).forEach(f=>copy(p.join(src, f), p.join(dest, f)));}}const args=Array.from(process.argv); copy(args[args.length-2], args[args.length-1]);" dist temp\dest

或者节点16.x+

node -e "const fs=require('fs');const args=Array.from(process.argv); fs.cpSync(args[args.length-2], args[args.length-1], {recursive: true});" 

在“节点14.20.0”上测试,但假设它在节点10.x上工作?

来自user8894303和pen的回答:https://stackoverflow.com/a/52338335/458321

如果在包中使用,请务必转义引号。json脚本

package.json:

  "scripts": {
    "rmrf": "node -e \"const fs=require('fs/promises');const args=Array.from(process.argv); Promise.allSettled(args.map(a => fs.rm(a, { recursive: true, force: true })));\"",
    "cp": "node -e \"const fs=require('fs');const args=Array.from(process.argv);if (args.length>2){ fs.cpSync(args[args.length-2], args[args.length-1], {recursive: true});}else{console.log('args missing', args);}\""
    "copy": "node -e \"const fs=require('fs');const p=require('path');function copy(src, dest) {if (!fs.existsSync(src)) {return;} if (fs.statSync(src).isFile()) {fs.copyFileSync(src, dest);}else{fs.mkdirSync(dest, {recursive: true});fs.readdirSync(src).forEach(f=>copy(p.join(src, f), p.join(dest, f)));}}const args=Array.from(process.argv);if (args.length>2){copy(args[args.length-2], args[args.length-1]);}else{console.log('args missing', args);}\"",
    "mkdir": "node -e \"const fs=require('fs');const args=Array.from(process.argv);fs.mkdirSync(args[args.length-1],{recursive:true});\"",
    "clean": "npm run rmrf -- temp && npm run mkdir -- temp && npm run copy -- dist temp"
  }

注:RMRF脚本需要14.20节点。X还是12.20.x?

奖金:

deno eval "import { existsSync, mkdirSync, copyFileSync, readdirSync, statSync } from 'node:fs';import { join } from 'node:path';function copy(src, dest) {if (!existsSync(src)) {return;} if (statSync(src).isFile()) {copyFileSync(src, dest);}else{mkdirSync(dest, {recursive: true});readdirSync(src).forEach(f=>copy(join(src, f), join(dest, f)));}}const args=Array.from(Deno.args);copy(args[0], args[1]);" dist temp\dest -- --allow-read --allow-write

Deno支持-> NPM I Deno -bin支持节点中的Deno -bin

对于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}`);

就是这样!

对于没有fs的旧节点版本。cp,我在紧要关头使用这个来避免需要第三方库:

const fs = require("fs").promises;
const path = require("path");

const cp = async (src, dest) => {
  const lstat = await fs.lstat(src).catch(err => false);

  if (!lstat) {
    return;
  }
  else if (await lstat.isFile()) {
    await fs.copyFile(src, dest);
  }
  else if (await lstat.isDirectory()) {
    await fs.mkdir(dest).catch(err => {});

    for (const f of await fs.readdir(src)) {
      await cp(path.join(src, f), path.join(dest, f));
    }
  }
};

// sample usage
(async () => {
  const src = "foo";
  const dst = "bar";

  for (const f of await fs.readdir(src)) {
    await cp(path.join(src, f), path.join(dst, f));
  }
})();

相对于现有答案的优势(或区别):

异步 忽略符号链接 如果目录已经存在,则不抛出(如果不需要,则不捕获mkdir抛出) 相当简洁的