node.js - readfilesync - fs write stream node js
fs.createWriteStream no crea inmediatamente el archivo? (3)
He hecho una descarga simple desde la función http como se muestra a continuación (el manejo de errores se omite para simplifcation):
function download(url, tempFilepath, filepath, callback) {
var tempFile = fs.createWriteStream(tempFilepath);
http.request(url, function(res) {
res.on(''data'', function(chunk) {
tempFile.write(chunk);
}).on(''end'', function() {
tempFile.end();
fs.renameSync(tempFile.path, filepath);
return callback(filepath);
})
});
}
Sin embargo, como llamo a download()
decenas de veces de forma asíncrona, rara vez informa de un error en fs.renameSync
quejándose de que no puede encontrar el archivo en tempFile.path
.
Error: ENOENT, no such file or directory ''xxx''
Usé la misma lista de URL para probarlo, y falló un 30% de las veces. La misma lista de direcciones URL funcionó cuando se descargó una por una.
Probando un poco más, descubrí que el siguiente código
fs.createWriteStream(''anypath'');
console.log(fs.exist(''anypath''));
console.log(fs.exist(''anypath''));
console.log(fs.exist(''anypath''));
no siempre se imprime true
, pero a veces la primera respuesta se imprime false
.
fs.createWriteStream
que demasiadas llamadas fs.createWriteStream
asíncronas no pueden garantizar la creación del archivo. ¿Es esto cierto? ¿Hay algún método para garantizar la creación de archivos?
Aquí está lo que yo uso para hacerlo:
function download(url, dest) {
return new Promise((resolve, reject) => {
http.get(url, (res) => {
if (res.statusCode !== 200) {
var err = new Error(''File couldn/'t be retrieved'');
err.status = res.statusCode;
return reject(err);
}
var chunks = [];
res.setEncoding(''binary'');
res.on(''data'', (chunk) => {
chunks += chunk;
}).on(''end'', () => {
var stream = fs.createWriteStream(dest);
stream.write(chunks, ''binary'');
stream.on(''finish'', () => {
resolve(''File Saved !'');
});
res.pipe(stream);
})
}).on(''error'', (e) => {
console.log("Error: " + e);
reject(e.message);
});
})
};
La respuesta aceptada no descargó algunos de los últimos bytes para mí.
Aquí hay una versión de Q que funciona correctamente (pero sin el archivo temporal).
''use strict'';
var fs = require(''fs''),
http = require(''http''),
path = require(''path''),
Q = require(''q'');
function download(url, filepath) {
var fileStream = fs.createWriteStream(filepath),
deferred = Q.defer();
fileStream.on(''open'', function () {
http.get(url, function (res) {
res.on(''error'', function (err) {
deferred.reject(err);
});
res.pipe(fileStream);
});
}).on(''error'', function (err) {
deferred.reject(err);
}).on(''finish'', function () {
deferred.resolve(filepath);
});
return deferred.promise;
}
module.exports = {
''download'': download
};
Tenga en cuenta que estoy escuchando para finish
el flujo de archivos en lugar de end
con la respuesta.
No debe llamar a write
en su tempFile
escritura tempFile
hasta que haya recibido el evento ''open''
del stream. El archivo no existirá hasta que vea ese evento.
Para su función:
function download(url, tempFilepath, filepath, callback) {
var tempFile = fs.createWriteStream(tempFilepath);
tempFile.on(''open'', function(fd) {
http.request(url, function(res) {
res.on(''data'', function(chunk) {
tempFile.write(chunk);
}).on(''end'', function() {
tempFile.end();
fs.renameSync(tempFile.path, filepath);
return callback(filepath);
});
});
});
}
Para su prueba:
var ws = fs.createWriteStream(''anypath'');
ws.on(''open'', function(fd) {
console.log(fs.existsSync(''anypath''));
console.log(fs.existsSync(''anypath''));
console.log(fs.existsSync(''anypath''));
});