Il progetto su cui sto lavorando (node.js) implica molte operazioni con il file system (copia / lettura / scrittura ecc.). Mi piacerebbe sapere quali sono i metodi più veloci e sarei felice di ricevere un consiglio. Grazie.
Il progetto su cui sto lavorando (node.js) implica molte operazioni con il file system (copia / lettura / scrittura ecc.). Mi piacerebbe sapere quali sono i metodi più veloci e sarei felice di ricevere un consiglio. Grazie.
Risposte:
Questo è un buon modo per copiare un file in una riga di codice usando gli stream:
var fs = require('fs');
fs.createReadStream('test.log').pipe(fs.createWriteStream('newLog.log'));
Nel nodo v8.5.0 è stato aggiunto copyFile
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');
});
createReadStreame createWriteStreamper gli errori, in modo da non ottiene una battuta (anche se sarebbe comunque altrettanto veloce).
cp test.log newLog.logvia require('child_process').exec?
copynon è portatile su Windows, contrariamente a una soluzione completa Node.js.
child_process.execFile('/bin/cp', ['--no-target-directory', source, target]).
fs.createReadStream('./init/xxx.json').pipe(fs.createWriteStream('xxx.json'));
Stesso meccanismo, ma questo aggiunge la gestione degli errori:
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;
}
}
}
WriteStreamsolo cancellarlo. Dovresti chiamarti rd.destroy(). Almeno questo è quello che mi è successo. Purtroppo non c'è molta documentazione se non dal codice sorgente.
cb? cosa dovremmo passare come terzo argomento?
Non sono riuscito a far funzionare il createReadStream/createWriteStreammetodo per qualche motivo, ma usando il fs-extramodulo npm ha funzionato immediatamente. Non sono sicuro della differenza di prestazioni però.
npm install --save fs-extra
var fs = require('fs-extra');
fs.copySync(path.resolve(__dirname,'./init/xxx.json'), 'xxx.json');
fs.copy(src, dst, callback);, e questi dovrebbero risolvere la preoccupazione di @ mvillar.
Da Node.js 8.5.0 abbiamo nuovi metodi fs.copyFile e fs.copyFileSync .
Esempio di utilizzo:
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');
});
copyFile()viene intercettato durante la sovrascrittura di file più lunghi. Per gentile concessione di uv_fs_copyfile()till Node v8.7.0 (libuv 1.15.0). vedi github.com/libuv/libuv/pull/1552
Veloce da scrivere e comodo da usare, con gestione promessa ed errore.
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;
});
}
Lo stesso con la sintassi asincrona / 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;
}
}
new Promise(function(resolve, reject) { resolve(1); resolve(2); reject(3); reject(4); console.log("DONE"); }).then(console.log.bind(console), function(e){console.log("E", e);});e cercato le specifiche su questo e hai ragione: tentare di risolvere o rifiutare una promessa risolta non ha alcun effetto. Forse potresti estendere la tua risposta e spiegare perché hai scritto la funzione in questo modo? Grazie :-)
closedovrebbe essere finishper flussi scrivibili.
/dev/stdin, questo è un bug github.com/joyent/node/issues/25375
Bene, di solito è bene evitare operazioni asincrone sui file. Ecco l'esempio di sincronizzazione breve (ovvero nessuna gestione degli errori):
var fs = require('fs');
fs.writeFileSync(targetFile, fs.readFileSync(sourceFile));
*Syncmetodi è totalmente contrario alla filosofia di nodejs! Penso anche che si stiano lentamente deprecando. L'idea generale di nodejs è che è single threaded e event-driven.
La soluzione di Mike Schilling con gestione degli errori con una scorciatoia per il gestore di eventi di errore.
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;
}
}
}
Se non ti interessa che sia asincrono e non stai copiando file di dimensioni gigabyte e preferisci non aggiungere un'altra dipendenza solo per una singola funzione:
function copySync(src, dest) {
var data = fs.readFileSync(src);
fs.writeFileSync(dest, data);
}
fs.existsSyncchiamata dovrebbe essere omessa. Il file potrebbe scomparire nel tempo tra la fs.existsSyncchiamata e la fs.readFileSyncchiamata, il che significa che la fs.existsSyncchiamata non ci protegge da nulla.
falsecaso di fs.existsSyncerrore è probabilmente una scarsa ergonomia perché pochi consumatori copySyncpensano di ispezionare manualmente il valore di ritorno ogni volta che viene chiamato, non più di quanto facciamo per fs.writeFileSync et al. . Generare un'eccezione è in realtà preferibile.
const fs = require("fs");
fs.copyFileSync("filepath1", "filepath2"); //fs.copyFileSync("file1.txt", "file2.txt");
Questo è ciò che uso personalmente per copiare un file e sostituire un altro file usando node.js :)
Per copie veloci dovresti usare il fs.constants.COPYFILE_FICLONE bandiera. Permette (per i filesystem che lo supportano) di non copiare effettivamente il contenuto del file. Viene creata solo una nuova voce di file, ma punta a una copia su scrittura "clone" del file di origine.
Non fare nulla / meno è il modo più veloce di fare qualcosa;)
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");
}
);
Usando invece le promesse:
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"));
fs.promises.copyFile
La soluzione di benweet che controlla la visibilità del file prima della copia:
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);
}
});
});
}
Perché non utilizzare la funzione di copia integrata nodejs?
Fornisce sia la versione asincrona che quella di sincronizzazione:
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
La soluzione di Mike , ma con le promesse:
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);
});
};
Miglioramento di un'altra risposta.
Caratteristiche:
promise, che ne semplifica l'utilizzo in un progetto più ampio.Uso:
var onePromise = copyFilePromise("src.txt", "dst.txt");
var anotherPromise = copyMultiFilePromise(new Array(new Array("src1.txt", "dst1.txt"), new Array("src2.txt", "dst2.txt")));
Codice:
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);
}
tutte le soluzioni di cui sopra che non verificano l'esistenza di un file sorgente sono pericolose ... ad es
fs.stat(source, function(err,stat) { if (err) { reject(err) }
in caso contrario, esiste un rischio in uno scenario nel caso in cui l'origine e la destinazione vengano sostituite per errore, i dati verranno persi in modo permanente senza notare alcun errore.