Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Download large file with node.js avoiding high memory consumption

I`m trying to create a file downloader as a background service but when a large file is scheduled, it's first put in memory and then, at the end of the download the file is written to disk.

How can I make the file be wrote gradually to the disk preserving memory considering that I may have lots of files being downloaded at the same time?

Here's the code I`m using:

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

});
like image 485
Carlosedp Avatar asked Jan 23 '11 00:01

Carlosedp


People also ask

Is Nodejs good for large applications?

It is suitable for large enterprise projects that do complex and complicated computations and data processing. The comparison in terms of development time between Node. js and Java is that, Node. js is easier to learn than Java, leading to faster development when using Node.

How much RAM does Nodejs need?

256 MB is sufficient amount of RAM to run Node. js (e.g. on Linux VPS instance), assuming no other memory-hog software is run.

How do I limit Node memory usage?

When Node. js applications are running within containers with memory limits set (using the --memory option for docker or any other flags with your orchestration system), use the --max-old-space-size option to ensure that Node knows its limit and that the set value is smaller than the container limit.

How many GB is node JS?

Out of the box, a 64-bit installation of node. js assumes a memory ceiling of 1.5GB per node process.

Why can’t I stream a large file in Node JS?

As it turns out, although Node.js is streaming the file input and output, in between it is still attempting to hold the entire file contents in memory, which it can’t do with a file that size. Node can hold up to 1.5GB in memory at one time, but no more.

What is the best tool to monitor memory usage in Node JS?

Aside from AppSignal to monitor your Node.js production setup, Node-Memwatch and Node-Inspector are great for debugging memory issues. P.S.

How do I read data from a file in Node JS?

The most straightforward is fs.readFile () wherein, the whole file is read into memory and then acted upon once Node has read it, and the second option is fs.createReadStream (), which streams the data in (and out) similar to other languages like Python and Java.

Is it possible to process large files in JavaScript?

Processing large files is nothing new to JavaScript, in fact, in the core functionality of Node.js, there are a number of standard solutions for reading and writing to and from files.


2 Answers

I changed the callback to:

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

    });

This worked perfectly.

like image 120
Carlosedp Avatar answered Oct 17 '22 10:10

Carlosedp


does the request package work for your uses?

it lets you do things like this:

request(downloadurl).pipe(fs.createWriteStream(downloadtohere))
like image 5
Carter Cole Avatar answered Oct 17 '22 12:10

Carter Cole