Maneira mais rápida de copiar o arquivo em node.js

O projeto em que estou trabalhando (node.js) implica em muitas operações com o sistema de arquivos (cópia / leitura / gravação, etc.). Eu gostaria de saber quais methods são os mais rápidos e ficaria feliz em receber alguns conselhos.

Essa é uma boa maneira de copiar um arquivo em uma linha de código usando streams:

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

O mesmo mecanismo, mas isso adiciona manipulação de erros:

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

Eu não era capaz de obter o método createReadStream/createWriteStream funcionando por algum motivo, mas usando fs-extra módulo fs-extra npm funcionou imediatamente. Não tenho certeza da diferença de desempenho.

fs-extra

npm install --save fs-extra

 var fs = require('fs-extra'); fs.copySync(path.resolve(__dirname,'./init/xxx.json'), 'xxx.json'); 

Rápido para escrever e conveniente de usar, com promise e gerenciamento de erros.

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

O mesmo com a syntax 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; } } 

Desde o Node.js 8.5.0, temos os novos methods fs.copyFile e fs.copyFileSync .

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

Bem, geralmente é bom evitar operações de arquivos asynchronouss. Aqui está o exemplo de synchronization curto (ou seja, sem tratamento de erros):

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

Solução de Mike Schilling com tratamento de erros com um atalho para o manipulador de events de erro.

 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 você não se importa com o fato de ser asynchronous e não copiar arquivos de tamanho gigabyte, prefere não adicionar outra dependência apenas para uma única function:

 function copySync(src, dest) { if (!fs.existsSync(src)) { return false; } var data = fs.readFileSync(src, 'utf-8'); fs.writeFileSync(dest, data); } 

Solução do benweet que verifica a visibilidade do arquivo antes da cópia:

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

A solução de Mike , mas com promises:

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

Melhoria de uma outra resposta.

Características:

  • Se as pastas dst não existirem, ele será criado automaticamente. A outra resposta só irá lançar erros.
  • Ele retorna uma promise , o que facilita o uso em um projeto maior.
  • Ele permite que você copie vários arquivos, e a promise será feita quando todos eles forem copiados.

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

todas as soluções acima que não verificam a existência de um arquivo de origem são perigosas … por exemplo

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

caso contrário, há um risco em um cenário no caso de a origem e o destino serem substituídos por um erro, seus dados serão permanentemente perdidos sem perceber qualquer erro.

Por que não usar o nodejs embutido na function de cópia?

Ele fornece a versão async e 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