简体   繁体   中英

Loop over uploaded files and return an array of file signatures

I want to loop over files selected for upload, get the file signature and return a array of file signatures. The listOfFileSignatures array is empty outside the readFirstFourBytes function. Is their a way to make it accessible globally?

var listOfFileSignatures = [];
var totalSize;
var uploadedFiles = document.getElementById("notes").files;
for (file of uploadedFiles) {
    var blob = file;
    var fileReader = new FileReader();
    fileReader.onloadend = function readFirstFourBytes(e) {
        var arr = (new Uint8Array(e.target.result)).subarray(0, 4);
        var fileSignature = "";
        for (var i = 0; i < arr.length; i++) {
            fileSignature += arr[i].toString(16);
        };
        listOfFileSignatures.push(fileSignature);
        console.log(listOfFileSignatures); // Array(3) [ "ffd8ffdb", "ffd8ffe0", "47494638" ]
    };
    fileReader.readAsArrayBuffer(blob);
};
console.log(listOfFileSignatures); // Array [] 

Heres the output

You can declare listOfFileSignatures globally, but the signatures are computed asynchronously, so the list will be empty directly after the for loop. FileReader is always asynchronous, so you can't avoid that. One possibility to handle this is to check if the list is full inside onloadend ( listOfFileSignatures.length == uploadedFiles.length ) and then do what you want there.

A nicer approach is to use promises, like this:

var uploadedFiles = document.getElementById("notes").files;

Promise.all([...uploadedFiles].map(file => new Promise((resolve, reject) => {
    var blob = file;

    var fileReader = new FileReader();
    fileReader.onloadend = function readFirstFourBytes(e) {
        var arr = (new Uint8Array(e.target.result)).subarray(0, 4);
        var fileSignature = "";
        for (var i = 0; i < arr.length; i++) {
            fileSignature += arr[i].toString(16);
        };
        resolve(fileSignature);
    };
    fileReader.readAsArrayBuffer(blob);

}))).then(function(listOfFileSignatures) {
    // this will be called once, when all results are collected.
    console.log(listOfFileSignatures);
});

Additionally, reading all bytes and then select just the first 4 byte is inefficient. Improved version:

Promise.all([...uploadedFiles].map(file => new Promise((resolve, reject) => {
    var blob = file;

    var fileReader = new FileReader();
    fileReader.onloadend = function readFirstFourBytes(e) {
        var arr = new Uint8Array(e.target.result);
        var fileSignature = "";
        for (var i = 0; i < arr.length; i++) {
            fileSignature += arr[i].toString(16);
        };
        resolve(fileSignature);
    };
    fileReader.readAsArrayBuffer(blob.slice(0, 4));

}))).then(function(listOfFileSignatures) {
    // this will be called once, when all results are collected.
    console.log(listOfFileSignatures);
});

fileReader.onload is asynchronous, console.log (listOfFileSignatures); is called before files have been read

one option is to create an external function that returns a promise, returning the listOfFileSignatures array

function getListFile() {
    return new Promise((resolve, reject) => { 
        var blob = file;
        var fileReader = new FileReader();
        fileReader.onloadend = function readFirstFourBytes(e) {
            var arr = (new Uint8Array(e.target.result)).subarray(0, 4);
            var fileSignature = "";
            for (var i = 0; i < arr.length; i++) {
                fileSignature += arr[i].toString(16);
            };
            listOfFileSignatures.push(fileSignature);
            resolve(listOfFileSignatures);
        };
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM