Подтвердить что ты не робот

Загрузите большой файл с помощью node.js, избегая потребления высокой памяти

Я пытаюсь создать загрузчик файлов в качестве фоновой службы, но когда запланирован большой файл, он сначала помещается в память, а затем, в конце загрузки, файл записывается на диск.

Как я могу заставить файл писать постепенно на память, сохраняющую память, учитывая, что у меня может быть много файлов, загружаемых одновременно?

Здесь код, который я использую:

var sys = require("sys"),
    http = require("http"),
    url = require("url"),
    path = require("path"),
    fs = require("fs"),
    events = require("events");

var downloadfile = "http://nodejs.org/dist/node-v0.2.6.tar.gz";

var host = url.parse(downloadfile).hostname
var filename = url.parse(downloadfile).pathname.split("/").pop()

var theurl = http.createClient(80, host);
var requestUrl = downloadfile;
sys.puts("Downloading file: " + filename);
sys.puts("Before download request");
var request = theurl.request('GET', requestUrl, {"host": host});
request.end();

var dlprogress = 0;


setInterval(function () {
   sys.puts("Download progress: " + dlprogress + " bytes");
}, 1000);


request.addListener('response', function (response) {
    response.setEncoding('binary')
    sys.puts("File size: " + response.headers['content-length'] + " bytes.")
    var body = '';
    response.addListener('data', function (chunk) {
        dlprogress += chunk.length;
        body += chunk;
    });
    response.addListener("end", function() {
        fs.writeFileSync(filename, body, 'binary');
        sys.puts("After download finished");
    });

});
4b9b3361

Ответ 1

Я изменил обратный вызов на:

request.addListener('response', function (response) {
        var downloadfile = fs.createWriteStream(filename, {'flags': 'a'});
        sys.puts("File size " + filename + ": " + response.headers['content-length'] + " bytes.");
        response.addListener('data', function (chunk) {
            dlprogress += chunk.length;
            downloadfile.write(chunk, encoding='binary');
        });
        response.addListener("end", function() {
            downloadfile.end();
            sys.puts("Finished downloading " + filename);
        });

    });

Это сработало отлично.

Ответ 2

Взгляните на http-request:

// shorthand syntax, buffered response
http.get('http://localhost/get', function (err, res) {
    if (err) throw err;
    console.log(res.code, res.headers, res.buffer.toString());
});

// save the response to 'myfile.bin' with a progress callback
http.get({
    url: 'http://localhost/get',
    progress: function (current, total) {
        console.log('downloaded %d bytes from %d', current, total);
    }
}, 'myfile.bin', function (err, res) {
    if (err) throw err;
    console.log(res.code, res.headers, res.file);
});

Ответ 3

При загрузке большого файла используйте fs.write, а не writeFile, так как он переопределит предыдущий контент.

function downloadfile(res) {
    var requestserver = http.request(options, function(r) {
        console.log('STATUS: ' + r.statusCode);
        console.log('HEADERS: ' + JSON.stringify(r.headers));

        var fd = fs.openSync('sai.tar.gz', 'w');

        r.on('data', function (chunk) {
            size += chunk.length;
            console.log(size+'bytes received');
            sendstatus(res,size);
            fs.write(fd, chunk, 0, chunk.length, null, function(er, written) {
            });
        });
        r.on('end',function(){
            console.log('\nended from server');
            fs.closeSync(fd);
            sendendstatus(res);
        });
    });
}

Ответ 4

работает ли пакет запросов для ваших целей?

он позволяет вам делать такие вещи:

request(downloadurl).pipe(fs.createWriteStream(downloadtohere))

Ответ 5

Вместо того, чтобы держать содержимое в памяти в прослушивателе событий "data", вы должны записать в файл в режиме добавления.

Ответ 6

Используйте потоки, такие как Картер Коул. Вот более полный пример

var inspect = require('eyespect').inspector();
var request = require('request');
var filed = require('filed');
var temp = require('temp');
var downloadURL = 'http://upload.wikimedia.org/wikipedia/commons/e/ec/Hazard_Creek_Kayaker.JPG';
var downloadPath = temp.path({prefix: 'singlePageRaw', suffix: '.jpg'});

var downloadFile = filed(downloadPath);
var r = request(downloadURL).pipe(downloadFile);


r.on('data', function(data) {
  inspect('binary data received');
});
downloadFile.on('end', function () {
  inspect(downloadPath, 'file downloaded to path');
});

downloadFile.on('error', function (err) {
  inspect(err, 'error downloading file');
});

Вам может потребоваться установить модули, которые вы можете выполнить через npm install filed request eyespect temp