web-dev-qa-db-fra.com

Moyen le plus rapide de copier le fichier dans node.js

Le projet sur lequel je travaille (node.js) implique de nombreuses opérations avec le système de fichiers (copie/lecture/écriture, etc.). J'aimerais savoir quelles méthodes sont les plus rapides et je serais heureux de vous conseiller.

399
bonbonez

C'est un bon moyen de copier un fichier dans une ligne de code à l'aide de flux:

var fs = require('fs');

fs.createReadStream('test.log').pipe(fs.createWriteStream('newLog.log'));

Dans le noeud 8.5.0, copyFile a été ajouté

const fs = require('fs');

// destination.txt will be created or overwritten by default.
fs.copyFile('source.txt', 'destination.txt', (err) => {
  if (err) throw err;
  console.log('source.txt was copied to destination.txt');
});
585

Même mécanisme, mais cela ajoute le traitement des erreurs:

function copyFile(source, target, cb) {
  var cbCalled = false;

  var rd = fs.createReadStream(source);
  rd.on("error", function(err) {
    done(err);
  });
  var wr = fs.createWriteStream(target);
  wr.on("error", function(err) {
    done(err);
  });
  wr.on("close", function(ex) {
    done();
  });
  rd.pipe(wr);

  function done(err) {
    if (!cbCalled) {
      cb(err);
      cbCalled = true;
    }
  }
}
285
Mike Schilling

Je n'ai pas pu faire fonctionner la méthode createReadStream/createWriteStream pour une raison quelconque, mais en utilisant le module fs-extra npm, cela a fonctionné immédiatement. Je ne suis cependant pas sûr de la différence de performance.

fs-extra

npm install --save fs-extra

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

fs.copySync(path.resolve(__dirname,'./init/xxx.json'), 'xxx.json');
131
Timmerz

Depuis Node.js 8.5.0, nous avons de nouvelles méthodes fs.copyFile et fs.copyFileSync .

Exemple d'utilisation:

var fs = require('fs');

// destination.txt will be created or overwritten by default.
fs.copyFile('source.txt', 'destination.txt', (err) => {
    if (err) throw err;
    console.log('source.txt was copied to destination.txt');
});
97
Mikhail

Rapide à écrire et pratique à utiliser, avec gestion des promesses et des erreurs.

function copyFile(source, target) {
  var rd = fs.createReadStream(source);
  var wr = fs.createWriteStream(target);
  return new Promise(function(resolve, reject) {
    rd.on('error', reject);
    wr.on('error', reject);
    wr.on('finish', resolve);
    rd.pipe(wr);
  }).catch(function(error) {
    rd.destroy();
    wr.end();
    throw error;
  });
}

Idem avec la syntaxe async/wait:

async function copyFile(source, target) {
  var rd = fs.createReadStream(source);
  var wr = fs.createWriteStream(target);
  try {
    return await new Promise(function(resolve, reject) {
      rd.on('error', reject);
      wr.on('error', reject);
      wr.on('finish', resolve);
      rd.pipe(wr);
    });
  } catch (error) {
    rd.destroy();
    wr.end();
    throw error;
  }
}
71
benweet

En règle générale, il est bon d’éviter les opérations de fichiers asynchrones. Voici l'exemple de synchronisation court (c'est-à-dire sans traitement d'erreur):

var fs = require('fs');
fs.writeFileSync(targetFile, fs.readFileSync(sourceFile));
38
Tester

Si vous ne vous souciez pas du fait qu'il soit asynchrone, ne copiez pas de fichiers de la taille d'un gigaoctet et préférez ne pas ajouter une autre dépendance pour une seule fonction:

function copySync(src, dest) {
  if (!fs.existsSync(src)) {
    return false;
  }

  var data = fs.readFileSync(src, 'utf-8');
  fs.writeFileSync(dest, data);
}
18
Andrew Childs

La solution de Mike Schilling avec la gestion des erreurs avec un raccourci pour le gestionnaire d'événements d'erreur.

function copyFile(source, target, cb) {
  var cbCalled = false;

  var rd = fs.createReadStream(source);
  rd.on("error", done);

  var wr = fs.createWriteStream(target);
  wr.on("error", done);
  wr.on("close", function(ex) {
    done();
  });
  rd.pipe(wr);

  function done(err) {
    if (!cbCalled) {
      cb(err);
      cbCalled = true;
    }
  }
}
18
Jens Hauke

la solution de benweet vérifiant la visibilité du fichier avant la copie:

function copy(from, to) {
    return new Promise(function (resolve, reject) {
        fs.access(from, fs.F_OK, function (error) {
            if (error) {
                reject(error);
            } else {
                var inputStream = fs.createReadStream(from);
                var outputStream = fs.createWriteStream(to);

                function rejectCleanup(error) {
                    inputStream.destroy();
                    outputStream.end();
                    reject(error);
                }

                inputStream.on('error', rejectCleanup);
                outputStream.on('error', rejectCleanup);

                outputStream.on('finish', resolve);

                inputStream.pipe(outputStream);
            }
        });
    });
}
1
Pedro Rodrigues

Amélioration d'une autre réponse.

Caractéristiques:

  • Si les dossiers dst n'existent pas, il sera automatiquement créé. L'autre réponse ne fera que jeter des erreurs.
  • Il retourne une promise, ce qui facilite son utilisation dans un projet plus important.
  • Il vous permet de copier plusieurs fichiers, et la promesse sera faite lorsque tous seront copiés.

Usage:

var onePromise = copyFilePromise("src.txt", "dst.txt");
var anotherPromise = copyMultiFilePromise(new Array(new Array("src1.txt", "dst1.txt"), new Array("src2.txt", "dst2.txt")));

Code:

function copyFile(source, target, cb) {
    console.log("CopyFile", source, target);

    var ensureDirectoryExistence = function (filePath) {
        var dirname = path.dirname(filePath);
        if (fs.existsSync(dirname)) {
            return true;
        }
        ensureDirectoryExistence(dirname);
        fs.mkdirSync(dirname);
    }
    ensureDirectoryExistence(target);

    var cbCalled = false;
    var rd = fs.createReadStream(source);
    rd.on("error", function (err) {
        done(err);
    });
    var wr = fs.createWriteStream(target);
    wr.on("error", function (err) {
        done(err);
    });
    wr.on("close", function (ex) {
        done();
    });
    rd.pipe(wr);
    function done(err) {
        if (!cbCalled) {
            cb(err);
            cbCalled = true;
        }
    }
}

function copyFilePromise(source, target) {
    return new Promise(function (accept, reject) {
        copyFile(source, target, function (data) {
            if (data === undefined) {
                accept();
            } else {
                reject(data);
            }
        });
    });
}

function copyMultiFilePromise(srcTgtPairArr) {
    var copyFilePromiseArr = new Array();
    srcTgtPairArr.forEach(function (srcTgtPair) {
        copyFilePromiseArr.Push(copyFilePromise(srcTgtPair[0], srcTgtPair[1]));
    });
    return Promise.all(copyFilePromiseArr);
}
0
fzyzcjy

La solution de Mike , mais avec des promesses:

const FileSystem = require('fs');

exports.copyFile = function copyFile(source, target) {
    return new Promise((resolve,reject) => {
        const rd = FileSystem.createReadStream(source);
        rd.on('error', err => reject(err));
        const wr = FileSystem.createWriteStream(target);
        wr.on('error', err => reject(err));
        wr.on('close', () => resolve());
        rd.pipe(wr);
    });
};
0
mpen

Pourquoi ne pas utiliser la fonction de copie intégrée de nodejs?

Il fournit à la fois la version asynchrone et sync:

const fs = require('fs');

// destination.txt will be created or overwritten by default.
fs.copyFile('source.txt', 'destination.txt', (err) => {
  if (err) throw err;
  console.log('source.txt was copied to destination.txt');
});

https://nodejs.org/api/fs.html#fs_fs_copyfilesync_src_dest_flags

0
Xin Wang

toutes les solutions ci-dessus qui ne vérifient pas l'existence d'un fichier source sont dangereuses ... par exemple.

fs.stat(source, function(err,stat) { if (err) { reject(err) }

sinon, dans un scénario, le risque existe si la source et la cible sont remplacées par une erreur, vos données seront définitivement perdues sans que vous ne remarquiez aucune erreur.

0
stancikcom

Pour les copies rapides, vous devez utiliser le drapeau fs.constants.COPYFILE_FICLONE. Cela permet (pour les systèmes de fichiers qui le supportent) de ne pas copier le contenu du fichier. Ne rien faire/moins est le moyen le plus rapide de faire quelque chose;)

https://nodejs.org/api/fs.html#fs_fs_copyfile_src_dest_flags_callback

let fs = require("fs");

fs.copyFile(
  "source.txt",
  "destination.txt",
  fs.constants.COPYFILE_FICLONE,
  (err) => {
    if (err) {
      // TODO: handle error
      console.log("error");
    }
    console.log("success");
  }
);

Utiliser des promesses à la place:

let fs = require("fs");
let util = require("util");
let copyFile = util.promisify(fs.copyFile);


copyFile(
  "source.txt",
  "destination.txt",
  fs.constants.COPYFILE_FICLONE
)
  .catch(() => console.log("error"))
  .then(() => console.log("success"));
0
chpio