Цикл по загруженным файлам и возвращает массив подписей файлов

#javascript #arrays #fileapi

#javascript #массивы #fileapi

Вопрос:

Я хочу перебирать файлы, выбранные для загрузки, получать подпись файла и возвращать массив подписей файлов. 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 [] 
 

Вот результат

Комментарии:

1. Вы нигде не объявляете listOfFileSignatures . ПЕРЕД for циклом просто добавьте listOfFileSignatures = [];

2. Объявите его глобально, просто поместите const listOfFileSignatures = [] перед for (file...) строкой.

3. @imvain2 У меня есть var listOfFileSignatures = []; перед циклом for.

4. @terrymorse У меня уже есть listOfFileSignatures цикл перед началом, я отредактировал пример кода.

5. @simanacci, поскольку у вас это объявлено, это означает, что проблема просто в том, что ваша консоль запускается ДО завершения всех ваших onloadend вызовов. Это означает, что вам нужно будет запустить функцию обратного вызова, которая использует listOfFileSignatures в onloadend ПОСЛЕДНЕГО файла в списке.

Ответ №1:

Вы можете объявить listOfFileSignatures глобально, но подписи вычисляются асинхронно, поэтому список будет пустым сразу после цикла for . FileReader всегда работает асинхронно, так что вы не можете избежать этого. Одна из возможностей справиться с этим — проверить, заполнен ли список внутри onloadend ( listOfFileSignatures.length == uploadedFiles.length ), а затем делать там то, что вы хотите.

Более приятный подход заключается в использовании обещаний, например:

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

Кроме того, чтение всех байтов, а затем выбор только первых 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);
});
 

Ответ №2:

FileReader.onload является асинхронным, console.log (listOfFileSignatures); вызывается до того, как файлы были прочитаны

одним из вариантов является создание внешней функции, которая возвращает обещание, возвращая массив 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);
        };
    }
}