218 votes

Copier un dossier de façon récursive dans Node.js

Existe-t-il un moyen plus simple de copier un dossier et tout son contenu sans effectuer manuellement une séquence de fs.readir , fs.readfile , fs.writefile de manière récursive ?

Je me demande simplement s'il ne me manque pas une fonction qui fonctionnerait idéalement comme ceci :

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

3voto

Elad Tal Points 21

J'ai écrit cette fonction pour copier (copyFileSync) ou déplacer (renameSync) des fichiers de manière récursive entre des répertoires :

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

3voto

Donovan P Points 144

Faites attention en choisissant votre paquet. Certains paquets, comme copy-dir, ne prennent pas en charge la copie de gros fichiers de plus de 0X1FFFFFE8 caractères (environ 537 Mo).

Il y aura une erreur comme :

buffer.js:630 Uncaught Error : Impossible de créer une chaîne de plus de 0x1fffffe8 caractères.

J'ai fait l'expérience de quelque chose comme cela dans l'un de mes projets. En fin de compte, j'ai dû changer le paquet que j'utilisais et ajuster beaucoup de code. Je dirais que ce n'est pas une expérience très agréable.

Si l'on souhaite obtenir plusieurs copies de la source et de la destination, on peut utiliser la fonction meilleure copie et écrire quelque chose comme ça :

// Copy from multiple source into a directory
bCopy(['/path/to/your/folder1', '/path/to/some/file.txt'], '/path/to/destination/folder');

Ou même :

// 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']);

3voto

Liakos Points 97

Utilisez shelljs

npm i -D shelljs

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

3voto

Benny Powers Points 1365

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

Notez bien l'utilisation de recursive: true . Cela empêche un ERR_FS_EISDIR error.

Plus d'informations sur le site Système de fichiers du nœud documentation

2voto

fuweichin Points 419

J'ai essayé fs-extra et copy-dir pour copier le dossier de manière récursive. mais je veux que cela soit

  1. fonctionnent normalement (copy-dir jette une erreur déraisonnable)
  2. fournir deux arguments dans le filtre : filepath et filetype (fs-extra ne dit pas filetype)
  3. avoir une vérification du répertoire au sous-répertoire et une vérification du répertoire au fichier.

Alors j'ai écrit le mien :

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

Et une fonction similaire, mkdirs qui est une alternative à 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`);
    }
  }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X