javascript - La forma más rápida de copiar el archivo en node.js
(13)
El proyecto en el que estoy trabajando (node.js) implica muchas operaciones con el sistema de archivos (copiar / leer / escribir, etc.). Me gustaría saber qué métodos son los más rápidos y me encantaría recibir algunos consejos.
Bueno, generalmente es bueno evitar operaciones de archivos asíncronas. Aquí está el ejemplo de sincronización corta (es decir, sin manejo de errores):
var fs = require(''fs'');
fs.writeFileSync(targetFile, fs.readFileSync(sourceFile));
Desde Node.js 8.5.0 tenemos nuevos métodos fs.copyFile y fs.copyFileSync .
Ejemplo de uso:
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'');
});
Esta es una buena manera de copiar un archivo en una línea de código usando flujos:
var fs = require(''fs'');
fs.createReadStream(''test.log'').pipe(fs.createWriteStream(''newLog.log''));
La solución de Benweet verifica la visibilidad del archivo antes de copiarlo:
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);
}
});
});
}
La solución de Mike Schilling con el manejo de errores con un atajo para el controlador de eventos de error.
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;
}
}
}
Mejora de otra respuesta.
caracteristicas:
- Si las carpetas dst no existen, las creará automáticamente. La otra respuesta solo arrojará errores.
- Devuelve una
promise
, lo que facilita su uso en un proyecto más grande. - Le permite copiar varios archivos, y se hará la promesa cuando se copien todos ellos.
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")));
Código:
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);
}
Mismo mecanismo, pero esto agrega manejo de errores:
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;
}
}
}
No pude hacer funcionar el método createReadStream/createWriteStream
por alguna razón, pero al usar fs-extra
módulo fs-extra
npm funcionó de inmediato. Aunque no estoy seguro de la diferencia de rendimiento.
npm install --save fs-extra
var fs = require(''fs-extra'');
fs.copySync(path.resolve(__dirname,''./init/xxx.json''), ''xxx.json'');
Rápido de escribir y conveniente de usar, con promesa y gestión de errores.
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 mismo con la sintaxis async / await:
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;
}
}
Si no te importa que sea asíncrono, y no estás copiando archivos del tamaño de un gigabyte, y preferirías no agregar otra dependencia solo para una sola función:
function copySync(src, dest) {
if (!fs.existsSync(src)) {
return false;
}
var data = fs.readFileSync(src, ''utf-8'');
fs.writeFileSync(dest, data);
}
todas las soluciones anteriores que no verifican la existencia de un archivo fuente son peligrosas ... por ejemplo,
fs.stat(source, function(err,stat) { if (err) { reject(err) }
de lo contrario, existe un riesgo en un escenario en el caso de que el origen y el destino se reemplacen por un error, sus datos se perderán permanentemente sin notar ningún error.
¿Por qué no usar nodejs construido en la función de copia?
Proporciona versiones asíncronas y sincronizadas:
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'');
});
La solución de Mike , pero con promesas:
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);
});
};