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