O projeto em que estou trabalhando (node.js) implica muitas operações com o sistema de arquivos (cópia / leitura / gravação etc.). Gostaria de saber quais métodos são os mais rápidos e ficaria feliz em receber um conselho. Obrigado.
O projeto em que estou trabalhando (node.js) implica muitas operações com o sistema de arquivos (cópia / leitura / gravação etc.). Gostaria de saber quais métodos são os mais rápidos e ficaria feliz em receber um conselho. Obrigado.
Respostas:
Esta é uma boa maneira de copiar um arquivo em uma linha de código usando fluxos:
var fs = require('fs');
fs.createReadStream('test.log').pipe(fs.createWriteStream('newLog.log'));
No nó v8.5.0, copyFile foi adicionado
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');
});
createReadStream
e os createWriteStream
erros, para não obter uma única linha (embora ainda seja tão rápido).
cp test.log newLog.log
via bruta require('child_process').exec
?
copy
não é portátil no Windows, ao contrário de uma solução completa do Node.js.
child_process.execFile('/bin/cp', ['--no-target-directory', source, target])
.
fs.createReadStream('./init/xxx.json').pipe(fs.createWriteStream('xxx.json'));
O mesmo mecanismo, mas isso adiciona o tratamento 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;
}
}
}
WriteStream
unpipe apenas. Você teria que se chamar rd.destroy()
. Pelo menos foi o que aconteceu comigo. Infelizmente, não há muita documentação, exceto o código-fonte.
cb
significa? o que devemos passar como terceiro argumento?
Não consegui fazer o createReadStream/createWriteStream
método funcionar por algum motivo, mas, usando o fs-extra
módulo npm, ele funcionou imediatamente. Não tenho certeza da diferença de desempenho.
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 estes devem resolver a preocupação de @ mvillar.
Desde Node.js 8.5.0 temos novos fs.copyFile e fs.copyFileSync métodos.
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');
});
copyFile()
erro ocorre ao substituir arquivos mais longos. Cortesia de uv_fs_copyfile()
até Node v8.7.0 (libuv 1.15.0). veja github.com/libuv/libuv/pull/1552
Rápido para escrever e conveniente de usar, com gerenciamento de promessas e 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 sintaxe assíncrona / aguardada:
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 procurei as especificações sobre isso e você está certo: Tentar resolver ou rejeitar uma promessa resolvida não tem efeito. Talvez você possa estender sua resposta e explicar por que você escreveu a função dessa maneira? Obrigado :-)
close
deve ser finish
para fluxos graváveis.
/dev/stdin
, isso é um bug github.com/joyent/node/issues/25375
Bem, geralmente é bom evitar operações de arquivo assíncronas. Aqui está o exemplo de sincronização curto (isto é, sem manipulação de erros):
var fs = require('fs');
fs.writeFileSync(targetFile, fs.readFileSync(sourceFile));
*Sync
métodos é totalmente contrário à filosofia dos nodejs! Eu também acho que eles estão sendo depreciados lentamente. A ideia do nodejs é que ele seja único e orientado a eventos.
A solução de Mike Schilling com tratamento de erros com um atalho para o manipulador de eventos 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 em ser assíncrono e não está copiando arquivos do tamanho de gigabytes, prefere não adicionar outra dependência apenas para uma única função:
function copySync(src, dest) {
var data = fs.readFileSync(src);
fs.writeFileSync(dest, data);
}
fs.existsSync
chamada deve ser omitida. O arquivo pode desaparecer no período entre a fs.existsSync
ligação e a fs.readFileSync
ligação, o que significa que a fs.existsSync
ligação não nos protege de nada.
false
se fs.existsSync
falhar provavelmente é uma ergonomia ruim, porque poucos consumidores copySync
pensam em inspecionar manualmente o valor de retorno toda vez que é chamado, assim como não fazemos para fs.writeFileSync
et al. . Lançar uma exceção é realmente preferível.
const fs = require("fs");
fs.copyFileSync("filepath1", "filepath2"); //fs.copyFileSync("file1.txt", "file2.txt");
É isso que eu pessoalmente uso para copiar um arquivo e substituir outro arquivo usando node.js :)
Para cópias rápidas, você deve usar a fs.constants.COPYFILE_FICLONE
bandeira. Ele permite que (para sistemas de arquivos que suportam isso) não copie o conteúdo do arquivo. Apenas uma nova entrada de arquivo é criada, mas aponta para uma cópia em gravação "clone" de do arquivo de origem.
Fazer nada / menos é a maneira mais rápida de fazer alguma coisa;)
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");
}
);
Em vez disso, usando promessas:
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
solução do benweet, verificando 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);
}
});
});
}
Por que não usar o nodejs construído na função de cópia?
Ele fornece as versões assíncrona e sincronizada:
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
A solução de Mike , mas com promessas:
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.
Recursos:
promise
, o que facilita o uso em um projeto maior.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, caso a origem e o destino sejam substituídos por engano, seus dados serão perdidos permanentemente sem perceber nenhum erro.