Question

Which is the simplest way to compare a hash of a file without storing it in a database?

For example:

var filename = __dirname + '/../public/index.html';
var shasum = crypto.createHash('sha1');

var s = fs.ReadStream(filename);
s.on('data', function(d) {
  shasum.update(d);
});

s.on('end', function() {
  var d = shasum.digest('hex');
  console.log(d + ' ' + filename);

  fs.writeFile(__dirname + "/../public/log.txt", d.toString() + '\n', function(err) {
     if(err) {
         console.log(err);
      } else {
         console.log("The file was saved!");
      }
  }); 
});

The above code returns the hash of the HTML file. If I edit the file how can I know if it has been changed? In other words, how can I know if the hash has been changed?

Any suggestions?

Edited

Now the hash is being saved in the log file. How can I retrieve the hash from the file and match it with the new generated one? A code example would be awesome to give me a better understanding.

There is no difference with this question, but it isn't clear for me yet how to implement it.

Was it helpful?

Solution

If you're looking for changes on a file, then you can use one of Node's filesystem functions, fs.watch. This is how it's used:

fs.watch(filename, function (event, filename) {
  //event is either 'rename' or 'change'
  //filename is the name of the file which triggered the event
});

The watch function is however not very consistent, so you can use fs.watchFile as an alternative. fs.watchFile uses stat polling, so it's quite a bit slower than fs.watch, which detects file changes instantly.

Watching a file will return an instance of fs.FSWatcher, which has the events change and error. Calling .close will stop watching for changes on the file.

Here's an example relating to your code:

var filename = __dirname + '/../public/index.html';
var shasum = crypto.createHash('sha1');

var oldhash = null;

var s = fs.ReadStream(filename);
s.on('data', function(d) {
  shasum.update(d);
});

s.on('end', function() {
  var d = shasum.digest('hex');
  console.log(d + ' ' + filename);
  oldhash = d.toString();

  fs.writeFile(__dirname + "/../public/log.txt", d.toString() + '\n', function(err) {
     if(err) {
         console.log(err);
      }
      else {
         console.log("The file was saved!");
      }
  }); 
});

//watch the log for changes
fs.watch(__dirname + "/../public/log.txt", function (event, filename) {
  //read the log contents
  fs.readFile(__dirname + "/../public/log.txt", function (err, data) {
    //match variable data with the old hash
    if (data == oldhash) {
      //do something
    }
  });
});

OTHER TIPS

What's the difference between this question and the previous one you asked? If you're not wanting to store it in a database, then store it as a file. If you want to save the hash for multiple files, then maybe put them in a JSON object and write them out as a .json file so they're easy to read/write.

EDIT

Given what you added to your question, it should be pretty simple. You might write a function to do check and re-write:

function updateHash (name, html, callback) {
    var sha = crypto.createHash('sha1');
    sha.update(html);
    var newHash = sha.digest('hex');

    var hashFileName = name + '.sha';

    fs.readFile(hashFileName, 'utf8', function (err, oldHash) {
        var changed = true;
        if (err)
            console.log(err); // probably indicates the file doesn't exist, but you should consider doing better error handling

        if (oldHash === newHash)
            changed = false;

        fs.writeFile(hashFileName, newHash, { encoding: 'utf8' }, function (err) {
            callback(err, changed);
        });
    });
}

updateHash('index.html', "<html><head><title>...", function (err, isChanged) {
    // do something with this information ?
    console.log(isChanged);
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top