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.
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');
});
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;
}
}
}
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.
npm install --save fs-extra
var fs = require('fs-extra');
fs.copySync(path.resolve(__dirname,'./init/xxx.json'), 'xxx.json');
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');
});
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;
}
}
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));
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);
}
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;
}
}
}
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);
}
});
});
}
Amélioration d'une autre réponse.
Caractéristiques:
promise
, ce qui facilite son utilisation dans un projet plus important.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);
}
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);
});
};
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
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.
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"));