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

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

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

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


当前回答

我写了这个函数用于在目录之间递归地复制(copyFileSync)或移动(renameSync)文件:

// Copy files
copyDirectoryRecursiveSync(sourceDir, targetDir);
// Move files
copyDirectoryRecursiveSync(sourceDir, targetDir, true);


function copyDirectoryRecursiveSync(source, target, move) {
    if (!fs.lstatSync(source).isDirectory())
        return;

    var operation = move ? fs.renameSync : fs.copyFileSync;
    fs.readdirSync(source).forEach(function (itemName) {
        var sourcePath = path.join(source, itemName);
        var targetPath = path.join(target, itemName);

        if (fs.lstatSync(sourcePath).isDirectory()) {
            fs.mkdirSync(targetPath);
            copyDirectoryRecursiveSync(sourcePath, targetPath);
        }
        else {
            operation(sourcePath, targetPath);
        }
    });
}

其他回答

挑选包裹时要小心。有些包(如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']);

看起来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)
}

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

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));
}

解决这个问题最简单的方法是只使用'fs'和'Path'模块和一些逻辑…

如果你只是想设置版本号,根文件夹中的所有文件都复制新名称,即" var v = '您的目录名'"

在文件名的前缀中添加带有文件名的内容。

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

var c = 0;
var i = 0;
var v = "1.0.2";
var copyCounter = 0;
var directoryCounter = 0;
var directoryMakerCounter = 0;
var recursionCounter = -1;
var Flag = false;
var directoryPath = [];
var directoryName = [];
var directoryFileName = [];
var fileName;
var directoryNameStorer;
var dc = 0;
var route;

if (!fs.existsSync(v)) {
    fs.mkdirSync(v);
}

var basePath = path.join(__dirname, v);


function walk(dir) {

    fs.readdir(dir, function(err, items) {

        items.forEach(function(file) {

            file = path.resolve(dir, file);

            fs.stat(file, function(err, stat) {

                if(stat && stat.isDirectory()) {
                    directoryNameStorer = path.basename(file);
                    route = file;
                    route = route.replace("gd", v);

                    directoryFileName[directoryCounter] = route;
                    directoryPath[directoryCounter] = file;
                    directoryName[directoryCounter] = directoryNameStorer;

                    directoryCounter++;
                    dc++;

                    if (!fs.existsSync(basePath + "/" + directoryName[directoryMakerCounter])) {
                        fs.mkdirSync(directoryFileName[directoryMakerCounter]);
                        directoryMakerCounter++;
                    }
                }
                else {
                    fileName = path.basename(file);
                    if(recursionCounter >= 0) {
                        fs.copyFileSync(file, directoryFileName[recursionCounter] + "/" + v + "_" + fileName, err => {
                            if(err) return console.error(err);
                        });
                        copyCounter++;
                    }
                    else {
                        fs.copyFileSync(file, v + "/" + v + "_" + fileName, err => {
                            if(err) return console.error(err);
                        });
                        copyCounter++;
                    }
                }
                if(copyCounter + dc == items.length && directoryCounter > 0 && recursionCounter < directoryMakerCounter-1) {
                    console.log("COPY COUNTER:             " + copyCounter);
                    console.log("DC COUNTER:               " + dc);
                    recursionCounter++;
                    dc = 0;
                    copyCounter = 0;
                    console.log("ITEM DOT LENGTH:          " + items.length);
                    console.log("RECURSION COUNTER:        " + recursionCounter);
                    console.log("DIRECOTRY MAKER COUNTER:  " + directoryMakerCounter);
                    console.log(": START RECURSION:        " + directoryPath[recursionCounter]);
                    walk(directoryPath[recursionCounter]); //recursive call to copy sub-folder
                }
            })
        })
    });
}

walk('./gd', function(err, data) { // Just pass the root directory which you want to copy
    if(err)
        throw err;
    console.log("done");
})

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