Learn how to download a file from the web with Electron using the request node module.

How to download a webfile with electron, save it and show download progress
Note: in this article, we are not going to use the download manager of Electron. This function aims to help you to download resources from remote sources easily (and most likely private, but not necessarily) with a couple of lines.

Sometimes, is not the user who needs to handle file downloads but you. Think about an application that requires some extra files to work as according to the every user, these files changes.

It wouldn't clever to let that the user handle the download of those files, as that's what Electron allow us to do, however that's not what we want.

In native languages like C#, Objective-C there are easy (theoretically) snippets that shows how to download a file in the OS without the user interaction. In this article we are going to expose a way in which you can download a file without so many workaround easily using Javascript in Electron with the help of node request library.

Requirements

Use the following command to include this library in your project :

npm install request

Downloading a file in your desktop

Before continue, declare the basic dependencies in the top of your script.

var request = require('request');
var fs = require('fs');

The filesystem will take care of write the file in our desktop while the request lib downloads it.

Request is designed to be the simplest way possible to make http calls. It supports HTTPS and follows redirects by default. The Request library has a lot of awesome features that you may want to explore before using it. Thanks to this library we'll be able to stream any response and save it into a file.

The magic occurs with createWriteStream, the function creates a writable stream in a very simple manner. After a call to fs.createWriteStream with the filepath, you have a writeable stream to work with. It turns out that the response (as well as the request) objects are streams. So we will stream the GET data to the file output.

Our solution is based on this principle and it's really easy to use and understand :

function downloadFile(file_url , targetPath){
    // Save variable to know progress
    var received_bytes = 0;
    var total_bytes = 0;

    var req = request({
        method: 'GET',
        uri: file_url
    });

    var out = fs.createWriteStream(targetPath);
    req.pipe(out);

    req.on('response', function ( data ) {
        // Change the total bytes value to get progress later.
        total_bytes = parseInt(data.headers['content-length' ]);
    });

    req.on('data', function(chunk) {
        // Update the received bytes
        received_bytes += chunk.length;

        showProgress(received_bytes, total_bytes);
    });

    req.on('end', function() {
        alert("File succesfully downloaded");
    });
}

function showProgress(received,total){
    var percentage = (received * 100) / total;
    console.log(percentage + "% | " + received + " bytes out of " + total + " bytes.");
}

Note

The progress is retrieven according to the filesize in bytes of the file and the total of received bytes (which are added to received_bytes on every data event).

To download a file, use the downloadFile method. This method expects as first parameter the web URL of the resource and as second parameter the local directory where the file will be saved (including filename and extension).

downloadFile("http://www.planwallpaper.com/static/images/butterfly-wallpaper.jpeg", "/var/www/downloads/butterfly-wallpaper.jpeg");

Finally, you only need to be worry about providing a valid local path. You can use a folder selector and then provide a filename, or just provide a static path and retrieve only the original name.

var fileURL = "http://www.planwallpaper.com/static/images/butterfly-wallpaper.jpeg";
// butterfly-wallpaper.jpeg
var filename = getFilenameFromUrl(fileURL);
var downloadsFolder = "C:\\Users\\sdkca\\Downloads";

function getFilenameFromUrl(url){
    return url.substring(url.lastIndexOf('/') + 1);
}

var finalPath = downloadsFolder + "\\" + filename;

downloadFile(fileURL, finalPath);

Promise based implementation

If you don't like to work with so many callbacks, then probably you are a Promises guy. The following snippet implements the same code to download a file but with promises:

/**
 * Promise based download file method
 */
function downloadFile(configuration){
    return new Promise(function(resolve, reject){
        // Save variable to know progress
        var received_bytes = 0;
        var total_bytes = 0;

        var req = request({
            method: 'GET',
            uri: configuration.remoteFile
        });

        var out = fs.createWriteStream(configuration.localFile);
        req.pipe(out);

        req.on('response', function ( data ) {
            // Change the total bytes value to get progress later.
            total_bytes = parseInt(data.headers['content-length' ]);
        });

        // Get progress if callback exists
        if(configuration.hasOwnProperty("onProgress")){
            req.on('data', function(chunk) {
                // Update the received bytes
                received_bytes += chunk.length;

                configuration.onProgress(received_bytes, total_bytes);
            });
        }else{
            req.on('data', function(chunk) {
                // Update the received bytes
                received_bytes += chunk.length;
            });
        }

        req.on('end', function() {
            resolve();
        });
    });
}

And its usage still very simple:

downloadFile({
    remoteFile: "http://www.planwallpaper.com/static/images/butterfly-wallpaper.jpeg",
    localFile: "/var/www/downloads/butterfly-wallpaper.jpeg",
    onProgress: function (received,total){
        var percentage = (received * 100) / total;
        console.log(percentage + "% | " + received + " bytes out of " + total + " bytes.");
    }
}).then(function(){
    alert("File succesfully downloaded");
});

Have fun


Senior Software Engineer at Software Medico. Interested in programming since he was 14 years old, Carlos is a self-taught programmer and founder and author of most of the articles at Our Code World.

Sponsors