ФС.createWriteStream не создает файл сразу?
Я сделал простую загрузку из http функции, как показано ниже (обработка ошибок опущена для упрощения):
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);
})
});
}
Однако, поскольку я вызываю download() десятки раз асинхронно, он редко сообщает об ошибке на fs.renameSync, жалуясь, что не может найти файл в tempFile.path.
Error: ENOENT, no such file or directory 'xxx'
Я использовал тот же список URL-адресов, чтобы проверить его, и он не удался примерно в 30% случаев. Один и тот же список URL-адресов работал при загрузке один за другим.
Протестировав еще немного, я обнаружил, что следующее код
fs.createWriteStream('anypath');
console.log(fs.exist('anypath'));
console.log(fs.exist('anypath'));
console.log(fs.exist('anypath'));
Не всегда печатает true, но иногда первый ответ печатает false.
Я подозреваю, что слишком много асинхронных fs.createWriteStream вызовов не могут гарантировать создание файла. Это правда? Существуют ли какие-либо методы, гарантирующие создание файлов?
3 ответов:
Вы не должны вызывать
writeв своем потоке записиtempFile, пока не получите событие'open'из потока. Файл не будет существовать, пока вы не увидите это событие.Для вашей функции:
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); }); }); }); }Для вашего теста:
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')); });
Принятый ответ не загрузил некоторые из последних байтов для меня.
Вот версия Q, которая работает правильно (но без временного файла).Обратите внимание, что я слушаю'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 };finishв файловом потоке вместоendв ответе.
Вот что я использую, чтобы это сделать:
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); }); }) };
Comments