Ba5t14n
Ba5t14n

Reputation: 739

synchronous hashing function for files

I have a function which generates a checksum for a given path

function getHash(path) {
     var fs = require('fs');
     var crypto = require('crypto');

     var fd = fs.createReadStream(path);
     var hash = crypto.createHash('sha1');
     hash.setEncoding('hex');

     fd.on('end', function () {
        hash.end();
        // *** Here is my problem ***
        console.log(hash.read()); 
     });

     fd.pipe(hash);
  };

I want to call the calcNewHash function so that it returns the hash, the problem is, that I haven't found an asynchronous version of this, maybe some one can help.

Just add a return statement doesn't work, because the function is in a Listener

Later I want to add the checksum to an object, so I could give the reference to it as parameter, but this still does not change that this is ansynchronous ...

Upvotes: 3

Views: 2897

Answers (2)

justFatLard
justFatLard

Reputation: 526

I know this is old but it is in the top results when searching for something along these lines. So for those that land here looking for a solution to this, here you go: (note that this only works well if you know the file is small. Otherwise for larger files refer to the answer provided by Dieterg)

const fs = require('fs');
const crypto = require('crypto');

function fileHashSync(filePath){
    var fileData;

    try{ fileData = fs.readFileSync(filePath, 'utf8'); }

    catch(err){
        if(err.code === 'ENOENT') return console.error('File does not exist. Error: ', err);

        return console.error('Error: ', err);
    }

    return crypto.createHash('sha1').update(fileData, 'utf8').digest('hex');
}

Upvotes: 5

Dieterg
Dieterg

Reputation: 16368

You basically have 2 solutions:

#1 Work with promises (i.e. q - npm install q --save)

function getHash(path) {
     var Q = require('q');
     var fs = require('fs');
     var crypto = require('crypto');

     var deferred = Q.defer();

     var fd = fs.createReadStream(path);
     var hash = crypto.createHash('sha1');
     hash.setEncoding('hex');

     fd.on('end', function () {
        hash.end();
        // *** Here is my problem ***
        console.log(hash.read()); 
        deferred.resolve(hash.read());
     });

     fd.pipe(hash);

     return deferred.promise;
};

getHash('c:\\')
   .then(function(result) {
     // do something with the hash result
   });

#2 Or use a callback function

function getHash(path, cb) {
     var fs = require('fs');
     var crypto = require('crypto');

     var fd = fs.createReadStream(path);
     var hash = crypto.createHash('sha1');
     hash.setEncoding('hex');

     fd.on('end', function () {
        hash.end();
        // *** Here is my problem ***
        console.log(hash.read()); 
        if (cb) {
          cb(null, hash.read());
        }
     });

     fd.pipe(hash);
};

getHash('C:\\', function (error, data) {
   if (!error) { 
      // do something with data
   } 
});

If you don't have deep nesting in callback functions I would go for option #2.

(Note: behind the scenes promises are also using callbacks, it's just a 'cleaner' solution if you have deep nesting)

Upvotes: 5

Related Questions