javascript node.js

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.

fs-extra

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

fs.copyFileSync


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