I have an input element on my html page, with which I can select 1/multiple file(s).
Once I have chosen my file(s), I would like to read the content of each file using a FileReader to make a SHA1 from it.
Once I have the SHA1 value, I would like to save it somewhere.
The problem is that I receive the SHA1 value only after the .onload of the FileReader is finished and that happens after I try to safe it's value.
I have tried to make the function async and using an await to wait until the file is read but that didn't work.
I have tried to add a Promise but that didn't work either.
I really don't know what to do to have the desired outcome. Please help.
This is my angular function that I call when I have choosen my file(s):
hashFiles(files: Array<any>){
console.log('start hashing');
for (const file of files) {
const myHash = hashFile(file);
console.log('hash: ', myHash);
/*I would like to save myHash here*/
}
console.log('done hashing');
}
This is my javascript function that's called from angular that will read the file with a FileReader and then make a sha1 hash from it's content
function hashFile(fileToHandle) {
console.log('1');
var reader = new FileReader();
console.log('2');
reader.onload = (function() {
return function(e) {
console.log('4');
const hash = CryptoJS.SHA1(arrayBufferToWordArray(e.target.result)).toString();
console.log('hash result in fileReader: ', hash);
return hash;
};
}) (fileToHandle);
reader.onerror = function(e) {
console.error(e);
};
console.log('3');
reader.readAsArrayBuffer(fileToHandle);
console.log('5');
}
function arrayBufferToWordArray(ab) {
var i8a = new Uint8Array(ab);
var a = [];
for (var i = 0; i < i8a.length; i += 4) {
a.push(i8a[i] << 24 | i8a[i + 1] << 16 | i8a[i + 2] << 8 | i8a[i + 3]);
}
return CryptoJS.lib.WordArray.create(a, i8a.length);
}
When running this code I have the following in my console:
start hashing
1
2
3
5
hash: undefined
done hashing
4
hash result in fileReader: 327c468b64b4ca54377546f8a214d703ccbad64b
And I need it to be:
start hashing
1
2
3
hash result in fileReader: 327c468b64b4ca54377546f8a214d703ccbad64b
4
5
hash: 327c468b64b4ca54377546f8a214d703ccbad64b
done hashing
Here is a sample of my code:
https://stackblitz.com/edit/sha1-from-file
You need to either work with call backs or add a promise wrapper (observable would also work) to the native callbacks of the FileReader
. Here is how you could do it just by adding a call back.
app.component.ts
hashFiles(event) {
console.log('start hashing');
const numberOfFiles = event.target.files.length;
var fileCounter = 0;
for (const file of event.target.files) {
hashFile(file, (hashedFile, hash) => {
console.log('hash: ', hash);
fileCounter++;
if(fileCounter === numberOfFiles)
console.log('Done Hashing!');
});
}
}
script.js
export function hashFile(fileToHandle, callback) {
var CryptoJS = require("crypto-js");
console.log('1');
var reader = new FileReader();
console.log('2');
reader.onloadend = (function() {
return function(e) {
console.log('4');
const hash = CryptoJS.SHA1(arrayBufferToWordArray(e.target.result)).toString();
console.log('hash result in fileReader: ', hash);
callback(fileToHandle, hash);
};
}) (fileToHandle);
reader.onerror = function(e) {
console.error(e);
};
console.log('3');
reader.readAsArrayBuffer(fileToHandle);
}