循环上传的文件和 return 一组文件签名

Loop over uploaded files and return an array of file signatures

我想循环选择要上传的文件,获取文件签名和return 一组文件签名。 listOfFileSignatures 数组在 readFirstFourBytes 函数之外是空的。他们是使其在全球范围内可访问的一种方式吗?

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

fileReader.onload是异步的,console.log(listOfFileSignatures);在读取文件之前被调用

一个选项是创建一个外部函数,returns一个承诺,返回 listOfFileSignatures 数组

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);
        };
    }
}

您可以全局声明 listOfFileSignatures,但签名是异步计算的,因此在 for 循环之后列表将直接为空。 FileReader 始终是异步的,因此您无法避免。处理这个问题的一种可能性是检查列表是否在 onloadend (listOfFileSignatures.length == uploadedFiles.length) 内已满,然后在那里做你想做的事。

更好的方法是使用 promises,如下所示:

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);
});

此外,读取所有字节然后 select 只读取前 4 个字节是低效的。改进版本:

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);
});