Изначально, загрузку сделал вот так:
export function сonvertFilesToByteArray(e) {
const MAX_FILE_SIZE = 1024 * 1024 * 50; // 50MB
const files = Object.keys(e.target.files);
const asyncReadFile = eachFile =>
new Promise((resolve, reject) => {
if (e.target.files[eachFile].size > MAX_FILE_SIZE) {
return reject([{ message: `Файл ${e.target.files[eachFile].name} слишком большой` }]);
}
const reader = new FileReader();
const targetFileInfo = {
contentType: e.target.files[eachFile].type,
filename: e.target.files[eachFile].name,
};
reader.readAsArrayBuffer(e.target.files[eachFile]);
reader.onload = () => {
resolve({ ...targetFileInfo, body: Array.from(new Uint8Array(reader.result)) });
};
reader.onerror = error => reject(error);
});
return Promise.all(files.map(asyncReadFile));
}
Тут в константе
files определяю, сколько у меня файлов и к каждому из них применяю функцию.
Но при таком подходе, не смотря на то, что использую Promise.all, при загрузке файла/файлов которые имеют размерность больше ~2МБ, то страница фризится, нельзя никак взаимодействовать с ней (скроллить есть возможность). Кроме как реализации, когда каждый файл бьётся по чанкам ничего в голову не пришло, чтобы исправить ситуацию.
Для этого переписал код на такой
export function сonvertFilesToByteArray(e) {
const MAX_FILE_SIZE = 1024 * 1024 * 50; // 50MB
const files = Object.keys(e.target.files);
const asyncReadFile = eachFile =>
new Promise((resolve, reject) => {
if (e.target.files[eachFile].size > MAX_FILE_SIZE) {
return reject([{ message: `Файл ${e.target.files[eachFile].name} слишком большой` }]);
}
const file = e.target.files[eachFile];
let offset = 0;
console.log(offset, 'offset', file.size, 'size');
const defaultChunkSize = 64 * 1024; // bytes
const fileReader = new FileReader();
const blob = file.slice(offset, offset + defaultChunkSize);
const isEndOfFile = () => offset >= file.size;
const testEndOfFile = () => {
if (isEndOfFile()) {
console.log('Done reading file');
}
};
fileReader.readAsArrayBuffer(blob);
fileReader.onloadend = (event) => {
const target = (event.target);
if (target.error == null) {
const result = target.result;
offset += result.length;
testEndOfFile();
console.log(result, 'result');
resolve(result);
} else {
reject(target.error);
}
};
});
return Promise.all(files.map(asyncReadFile));
}
Но тут я уперся в то, что не понимаю, как прочитать файл по чанкам (если он больше одного) и собрать его воедино, чтобы на выходе получить массив байтов и как в первом примере скомпоновать объект вида
{contentType: 'plain/text', filename: 'blabla', body: и вот тут мой буффер вида [123, 456, 23, ...] }
Который при завершении чтении всех файлов перебросится наружу, где написал следующий код
handleFileUpload = (e) => {
сonvertFilesToByteArray(e)
.then((result) => {
runInAction(() => {
this.files = [
...this.files,
...result,
];
});
})
.catch(err => runInAction(() => {
this.errors = [...this.errors, err[0].message];
}));
}
Комрады, выручайте :)