web-dev-qa-db-fra.com

Copier le dossier récursivement 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?

Je me demande juste s'il me manque une fonction qui fonctionnerait idéalement comme ceci

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

Vous pouvez utiliser ncp module. Je pense que c'est ce dont tu as besoin

89
shift66

Ceci est mon approche pour résoudre ce problème sans aucun module supplémentaire. En utilisant simplement les modules fs et path intégrés.

Note: Ceci utilise les fonctions lecture/écriture de fs, donc il ne copie aucune métadonnée (heure de création, etc.). À partir du noeud 8.5, il existe une copyFileSync fonctions disponibles qui appellent les fonctions de copie du système d'exploitation et, par conséquent, copient également les métadonnées. Je ne les ai pas encore testés, mais cela devrait fonctionner pour les remplacer. (Voir 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 );
            }
        } );
    }
}
52
Simon Zyx

Certains modules prennent en charge la copie de dossiers avec leur contenu. Le plus populaire serait clé

// Deep-copy an existing directory
wrench.copyDirSyncRecursive('directory_to_copy', 'location_where_copy_should_end_up');

Une alternative serait 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
40
zemirco
/**
 * 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.linkSync(src, dest);
  }
};
21
Lindsey Simon

fs-extra a fonctionné pour moi lorsque ncp et wrench ont échoué:

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

19
Will

Pour les systèmes d'exploitation Linux/Unix, vous pouvez utiliser la syntaxe Shell  

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

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

Shell(`mkdir -p ${dist}`);
Shell(`cp -r ${src}/* ${dist}`);

C'est tout!

11
Abdennour TOUMI

J'ai créé un petit exemple de travail qui copie un dossier source dans un autre dossier de destination en quelques étapes seulement (en fonction de la réponse @ shift66 à l'aide de ncp):

étape 1 - Installer le module ncp:

npm install ncp --save

étape 2 - créer un fichier copy.js (modifiez les variables srcPath et destPath en fonction de vos besoins):

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

étape 3 - courir

node copy.js
10
Shahar

le module fs-extra fonctionne à merveille.

Installer fs-extra

$ npm install fs-extra

Voici le programme pour copier le répertoire source dans le répertoire de destination.

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

Références

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

Exemple: Tutoriel Node.js - Node.js Copier un dossier

6
Mallikarjun M

@ mallikarjun-m merci!

fs-extra a fait la chose et il peut même retourner Promise si vous ne fournissez pas de rappel! :)

const path = require('path')
const fs = require('fs-extra')

let source = path.resolve( __dirname, 'folderA')
let destination = path.resolve( __dirname, 'folderB')

fs.copy(source, destination)
  .then(() => console.log('Copy completed!'))
  .catch( err => {
    console.log('An error occured while copying the folder.')
    return console.error(err)
  })
4
Luckylooke

Comme je ne fais que construire un script de noeud simple, je ne voulais pas que les utilisateurs du script aient besoin d'importer un ensemble de modules externes et de dépendances. Coquille.

Cet extrait de code node.js copie de manière récursive un dossier appelé node-webkit.app dans un dossier appelé build:

   child = exec("cp -r node-webkit.app build", function(error, stdout, stderr) {
        sys.print("stdout: " + stdout);
        sys.print("stderr: " + stderr);
        if(error !== null) {
            console.log("exec error: " + error);
        } else {

        }
    });

Merci à Lance Pollard de dzone pour m'avoir lancé.

L'extrait de code ci-dessus est limité aux plates-formes Unix telles que Mac OS et Linux, mais une technique similaire peut fonctionner pour Windows.

3
jmort253

C'est assez facile avec le noeud 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);
        }
    }
}

Cela suppose que dest n'existe pas.

2
mpen

Voici comment je le ferais personnellement:

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

fonctionne pour les dossiers et les fichiers

1
BreakTruth

Voici comment j'ai fait:

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

puis:

let filePath = //your FilePath

let fileList = []
        var walkSync = function(filePath, filelist) 
        {
          let files = fs.readdirSync(filePath);
          filelist = filelist || [];
          files.forEach(function(file) 
          {
            if (fs.statSync(path.join(filePath, file)).isDirectory()) 
            {
              filelist = walkSync(path.join(filePath, file), filelist);
            }
            else 
            {
              filelist.Push(path.join(filePath, file));
            }
          });

          // Ignore hidden files
          filelist = filelist.filter(item => !(/(^|\/)\.[^\/\.]/g).test(item));

          return filelist;
        };

Puis appelez la méthode:

This.walkSync(filePath, fileList)
0
uyghurbeg

J'ai écrit cette fonction à la fois pour copier (copyFileSync) ou déplacer (renameSync) 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, targetDir);
    }
    else {
        operation(sourcePath, targetPath);
    }
});}
0
Elad Tal

Ce code fonctionnera très bien, copiant récursivement n'importe quel dossier vers n'importe quel emplacement Windows uniquement.

var child=require("child_process");
function copySync(from,to){
    from=from.replace(/\//gim,"\\");
    to=to.replace(/\//gim,"\\");
    child.exec("xcopy /y /q \""+from+"\\*\" \""+to+"\\\"");
}

Fonctionne parfaitement pour mon jeu basé sur le texte pour la création de nouveaux joueurs.

0

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

  1. fonctionne normalement (le répertoire de copie génère une erreur impossible à résorber)
  2. fournit deux arguments dans le filtre: filepath et filetype (fs-extra n'indique pas filetype)
  3. a une vérification de répertoire à sous-répertoire et une vérification de répertoire à fichier

Alors j'ai écrit le mien:

//node module for node 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`);
    }
  }
}
0
fuweichin

L'approche la plus simple pour ce problème consiste à utiliser uniquement les modules 'fs' et 'Path', ainsi que de la logique .....

Tous les fichiers du dossier racine copiés avec le nouveau nom si vous souhaitez simplement définir le numéro de version, par exemple ....................... "" var v = 'Votre répertoire Prénom'"

dans Préfixe du nom de fichier, contenu V ajouté au nom de fichier. 

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");
})
0
MM Furkan

YES, ncp est cool quoique ...

Vous voudrez peut-être/devriez promettre que sa fonction donnerait super cool. Puisque vous y êtes, ajoutez-le à un fichier tools pour le réutiliser.

Vous trouverez ci-dessous une version de travail qui s'appelle Async et utilise Promises.


index.js

const {copyFolder} = require('./tools/');

return copyFolder(
    yourSourcePath,
    yourDestinationPath
)
.then(() => {
    console.log('-> Backup completed.')
}) .catch((err) => {
    console.log("-> [ERR] Could not copy the folder: ", err);
})

tools.js

const ncp = require("ncp");

/**
 * Promise Version of ncp.ncp()
 * 
 * This function promisifies ncp.ncp().
 * We take the asynchronous function ncp.ncp() with 
 * callback semantics and derive from it a new function with
 * promise semantics.
 */
ncp.ncpAsync = function (sourcePath, destinationPath) {
  return new Promise(function (resolve, reject) {
      try {
          ncp.ncp(sourcePath, destinationPath, function(err){
              if (err) reject(err); else resolve();
          });
      } catch (err) {
          reject(err);
      }
  });
};

/**
 * Utility function to copy folders asynchronously using
 * the Promise returned by ncp.ncp(). 
 */
const copyFolder = (sourcePath, destinationPath) => {
    return ncp.ncpAsync(sourcePath, destinationPath, function (err) {
        if (err) {
            return console.error(err);
        }
    });
}
module.exports.copyFolder = copyFolder;
0
Mick