Node.js: Compare directory contents with file checksums asynchronously
sha256, checksum, async, await, es6
Comparing the content of two directories binary-safe is a common used feature especially for data synchronization tasks. You can easily implement a simple compare algorithm by generating the sha256 checksums of each file – this is not a high-performance solution but even works on large files!
const _fs = require('fs-magic');
// compare directoy contents based on sha256 hash tables
async function compareDirectories(dir1, dir2){
// fetch file lists
const [files1, dirs1] = await _fs.scandir(dir1, true, true);
const [files2, dirs2] = await _fs.scandir(dir2, true, true);
// num files, directories equal ?
if (files1.length != files2.length){
throw new Error('The directories containing a different number of files ' + files1.length + '/' + files2.length);
}
if (dirs1.length != dirs2.length){
throw new Error('The directories containing a different number of subdirectories ' + dirs1.length + '/' + dirs2.length);
}
// generate file checksums
const hashes1 = await Promise.all(files1.map(f => _fs.sha256file(f)));
const hashes2 = await Promise.all(files2.map(f => _fs.sha256file(f)));
// convert arrays to objects filename=>hash
const lookup = {};
for (let i=0;i<hashes2.length;i++){
// normalized filenames
const f2 = files2[i].substr(dir2.length);
// assign
lookup[f2] = hashes2[i];
}
// compare dir1 to dir2
for (let i=0;i<hashes1.length;i++){
// normalized filenames
const f1 = files1[i].substr(dir1.length);
// exists ?
if (!lookup[f1]){
throw new Error('File <' + files1[i] + '> does not exist in <' + dir2 + '>');
}
// hash valid ?
if (lookup[f1] !== hashes1[i]){
throw new Error('File Checksum of <' + files1[i] + '> does not match <' + files2[i] + '>');
}
}
return true;
}
await compareDirectories('/tmp/data0', '/tmp/data1');