在node.js中递归复制文件夹

los*_*rce 128 javascript node.js

是否有一个文件夹及其内容全部复制,而无需手动做的序列更简单的方法fs.readir,fs.readfile,fs.writefile递归?

只是想知道我是否错过了一个理想的工作方式

fs.copy("/path/to/source/folder","/path/to/destination/folder");
Run Code Online (Sandbox Code Playgroud)

Jax*_*x-p 120

从 Node v16.7.0 开始,就可以使用fs.cpfs.cpSync运行。

fs.cp(src, dest, {recursive: true}, (err) => {/* callback */});
// Or
fs.cpSync(src, dest, {recursive: true});
Run Code Online (Sandbox Code Playgroud)

当前稳定性(在 Node v21.1.0 中)处于实验阶段

  • 我想使用它,但是,嗯,正如链接所说,“_稳定性:1 - 实验性。该功能不受语义版本控制规则的约束。在任何未来版本中可能会发生非向后兼容的更改或删除。该功能的使用不建议在生产环境中使用。_” (2认同)

shi*_*t66 109

您可以使用ncp模块.我想这就是你需要的

  • 请注意,ncp [似乎没有维护](https://github.com/AvianFlu/ncp/issues/85).[fs-extra](https://github.com/jprichardson/node-fs-extra)可能是最好的选择. (26认同)
  • 作为一个惊人的奖励,可以在跨平台的npm运行脚本中使用ncp. (3认同)
  • 完美的!`npm install ncp` 并在不到 30 秒内工作。谢谢。 (2认同)

Sim*_*Zyx 65

这是我在没有任何额外模块的情况下解决此问题的方法.只需使用内置fspath模块.

注意:这确实使用了fs的读/写功能,因此它不会复制任何元数据(创建时间等).从节点8.5开始,有一个copyFileSync可用的函数调用OS复制函数,因此也复制元数据.我还没有测试它们,但它应该可以替换它们.(参见https://nodejs.org/api/fs.html#fs_fs_copyfilesync_src_dest_flags)

var fs = require('fs');
var path = require('path');

function copyFileSync( source, target ) {

    var targetFile = target;

    //if target is a directory a new file with the same name will be created
    if ( fs.existsSync( target ) ) {
        if ( fs.lstatSync( target ).isDirectory() ) {
            targetFile = path.join( target, path.basename( source ) );
        }
    }

    fs.writeFileSync(targetFile, fs.readFileSync(source));
}

function copyFolderRecursiveSync( source, target ) {
    var files = [];

    //check if folder needs to be created or integrated
    var targetFolder = path.join( target, path.basename( source ) );
    if ( !fs.existsSync( targetFolder ) ) {
        fs.mkdirSync( targetFolder );
    }

    //copy
    if ( fs.lstatSync( source ).isDirectory() ) {
        files = fs.readdirSync( source );
        files.forEach( function ( file ) {
            var curSource = path.join( source, file );
            if ( fs.lstatSync( curSource ).isDirectory() ) {
                copyFolderRecursiveSync( curSource, targetFolder );
            } else {
                copyFileSync( curSource, targetFolder );
            }
        } );
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这实际上并不复制文件。它先读取它们,然后写入它们。那不是复制。复制包括创建日期以及Windows和MacOS支持的其他元数据流,并且此代码不会复制这些元数据流。从节点8.5开始,您应该调用“ fs.copy”或“ fs.copySync”,因为它们实际上调用了MacOS和Windows中的OS级复制功能,因此实际上是复制文件。 (2认同)

Ary*_*rya 55

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

The Developer of Wrench 指导用户使用,fs-extra因为他已经弃用了他的库

copySyncmoveSync都将复制和移动文件夹,即使它们有文件或子文件夹,您可以使用它轻松移动或复制文件

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

const srcDir = `path/to/file`;
const destDir = `path/to/destination/directory`;
                              
// To copy a folder or file  
fse.copySync(srcDir, destDir, function (err) {
  if (err) {                 ^
    console.error(err);      |___{ overwrite: true } // add if you want to replace existing folder or file with same name
  } else {
    console.log("success!");
  }
});
Run Code Online (Sandbox Code Playgroud)

或者

// To copy a folder or file  
fse.moveSync(srcDir, destDir, function (err) {
  if (err) {                 ^
    console.error(err);      |___{ overwrite: true } // add if you want to replace existing folder or file with same name
  } else {
    console.log("success!");
  }
});
Run Code Online (Sandbox Code Playgroud)

  • fse copySync 不接受回调:https://github.com/jprichardson/node-fs-extra/blob/HEAD/docs/copy-sync.md。如果你想检测错误,你应该尝试捕获: `try { fse.copySync('/tmp/myfile', '/tmp/mynewfile'); console.log('成功!');} catch (err) { console.error(err);}` (4认同)

zem*_*rco 48

有些模块支持使用其内容复制文件夹.最受欢迎的是扳手

// Deep-copy an existing directory
wrench.copyDirSyncRecursive('directory_to_copy', 'location_where_copy_should_end_up');
Run Code Online (Sandbox Code Playgroud)

另一种选择是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
Run Code Online (Sandbox Code Playgroud)

  • 请注意,`扳手`已被弃用,应替换为`node-fs-extra`(https://github.com/jprichardson/node-fs-extra) (13认同)
  • node-fs-extra为我工作.它继承了原始的fs,我喜欢它处理这个过程的方式.在应用中更新的代码更少. (6认同)
  • 如果要复制的目录包含符号链接,则扳手失败 (3认同)
  • 在窗户试过扳手.copyDirSyncRecursive不起作用. (3认同)
  • 如果目录已经存在,它也会在Windows上失败,[ncp](https://npmjs.org/package/ncp)正好工作. (2认同)

小智 28

fs-extra为我工作的时间ncpwrench不足之处:

https://www.npmjs.com/package/fs-extra

  • 此外,“ wrench”的开发者指示用户使用“ fs-extra”,因为他已经弃用了自己的库。 (2认同)
  • 请您提供一些工作代码示例 (2认同)

Lin*_*mon 26

/**
 * Look ma, it's cp -R.
 * @param {string} src The path to the thing to copy.
 * @param {string} dest The path to the new copy.
 */
var copyRecursiveSync = function(src, dest) {
  var exists = fs.existsSync(src);
  var stats = exists && fs.statSync(src);
  var isDirectory = exists && stats.isDirectory();
  if (exists && isDirectory) {
    fs.mkdirSync(dest);
    fs.readdirSync(src).forEach(function(childItemName) {
      copyRecursiveSync(path.join(src, childItemName),
                        path.join(dest, childItemName));
    });
  } else {
    fs.copyFile(src, dest);    // UPDATE FROM:    fs.linkSync(src, dest);
  }
};
Run Code Online (Sandbox Code Playgroud)

  • 这个功能不会复制它只是链接所有文件! (4认同)
  • 可以优化为`if(isDirectory)` - `isDirectory`已经检查`exists`. (3认同)
  • 可能导致这种混淆的是fs.unlink删除文件,但fs.link不复制但链接. (3认同)
  • @SimonSeyock:是的.. IT正在“链接”而不是复制..问题是,当您修改链接文件的内容时,原始文件也会更改。 (3认同)
  • 即使您要插入真正的复制功能,也不应该遵循符号链接(使用`fs.lstatSync`而不是`fs.statSync`) (2认同)

Abd*_*UMI 19

对于linux/unix OS,您可以使用shell语法

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

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

shell(`mkdir -p ${dist}`);
shell(`cp -r ${src}/* ${dist}`);
Run Code Online (Sandbox Code Playgroud)

而已!

  • 因为nodejs在OSX/linux/windows上运行,所以这只是2而不是全部3的答案. (9认同)
  • 这就是为什么我从“对于 linux/unix 操作系统,您可以使用 shell 语法..”开始回答的原因。 (6认同)
  • @AbdennourTOUMI如果您在Windows服务器上运行该怎么办? (2认同)

Mal*_*n M 14

fs-extra模块就像一个魅力.

安装fs-extra

$ npm install fs-extra
Run Code Online (Sandbox Code Playgroud)

以下是将源目录复制到目标目录的程序.

// include fs-extra package
var fs = require("fs-extra");

var source = 'folderA'
var destination = 'folderB'

// copy source folder to destination
fs.copy(source, destination, function (err) {
    if (err){
        console.log('An error occured while copying the folder.')
        return console.error(err)
    }
    console.log('Copy completed!')
});
Run Code Online (Sandbox Code Playgroud)

参考

fs-extra:https://www.npmjs.com/package/fs-extra

示例:Node.js教程 - Node.js复制文件夹


mpe*_*pen 14

这对于 Node.js 10 来说非常简单:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这假设dest不存在。

  • 我们可以通过使用 `require('util').promisify` 和 `fs.mkdir` 和 `fs.copyFile` 而不是 `require('fs').promises` 来让它在 Node 8.x 中工作,它是在 v11.1 仍处于实验阶段。 (3认同)

Fre*_*iel 12

我知道这里已经有很多答案,但没有人以简单的方式回答。

关于 fs-exra官方文档,你可以很容易地做到。

const fs = require('fs-extra')

// Copy file
fs.copySync('/tmp/myfile', '/tmp/mynewfile')

// Copy directory, even if it has subdirectories or files
fs.copySync('/tmp/mydir', '/tmp/mynewdir')

Run Code Online (Sandbox Code Playgroud)


Sha*_*har 9

我创建了一个小工作示例,只需几步即可将源文件夹复制到另一个目标文件夹(基于使用ncp的@shift66 answer):

第1步 - 安装ncp模块:

npm install ncp --save
Run Code Online (Sandbox Code Playgroud)

第2步 - 创建copy.js(将srcPath和destPath变量修改为您需要的任何内容):

var path = require('path');
var ncp = require('ncp').ncp;

ncp.limit = 16;

var srcPath = path.dirname(require.main.filename); //current folder
var destPath = '/path/to/destination/folder'; //Any destination folder

console.log('Copying files...');
ncp(srcPath, destPath, function (err) {
  if (err) {
    return console.error(err);
  }
  console.log('Copying files complete.');
});
Run Code Online (Sandbox Code Playgroud)

第3步 - 运行

node copy.js
Run Code Online (Sandbox Code Playgroud)


all*_*llx 8

支持符号链接的那个:

import path from "path"
import {
  existsSync, mkdirSync, readdirSync, lstatSync,
  copyFileSync, symlinkSync, readlinkSync
} from "fs"


export function copyFolderSync(src, dest) {
  if (!existsSync(dest)) mkdirSync(dest)

  readdirSync(src).forEach(dirent => {
    const [srcPath, destPath] = [src, dest].map(dirPath => path.join(dirPath, dirent))
    const stat = lstatSync(srcPath)

    switch (true) {
      case stat.isFile():
        copyFileSync(srcPath, destPath); break
      case stat.isDirectory():
        copyFolderSync(srcPath, destPath); break
      case stat.isSymbolicLink():
        symlinkSync(readlinkSync(srcPath), destPath); break
    }
  })
}

Run Code Online (Sandbox Code Playgroud)


小智 7

这是我个人要做的:

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));
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

适用于文件夹和文件

  • 这个解决方案简洁明了。这几乎就是我要做的,所以我给了 +1。您应该在代码中添加注释来改进答案,并描述为什么该解决方案优于其他解决方案以及它可能有哪些缺点。-- 同时更新它需要的模块。(“路径”,“fs”) (4认同)
  • 检查顶部的文件夹是否存在...将挽救生命;-) if (!fs.existsSync(to)) fs.mkdirSync(to); (3认同)

Ben*_*ers 5

从节点 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,
  }
);
Run Code Online (Sandbox Code Playgroud)

仔细注意使用recursive: true。这可以防止ERR_FS_EISDIR错误。

阅读有关节点文件系统文档的更多信息