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

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

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

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


当前回答

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

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

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

其他回答

打印稿版本

async function copyDir(source: string, destination: string): Promise<any> {
  const directoryEntries = await readdir(source, { withFileTypes: true });
  await mkdir(destination, { recursive: true });

  return Promise.all(
    directoryEntries.map(async (entry) => {
      const sourcePath = path.join(source, entry.name);
      const destinationPath = path.join(destination, entry.name);

      return entry.isDirectory()
        ? copyDir(sourcePath, destinationPath)
        : copyFile(sourcePath, destinationPath);
    })
  );
}

使用 shelljs

npm i -D shelljs

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

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

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

这在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不存在。

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