Я ищу способ разделить любой текстовый файл / файл данных на передней панели браузера перед загрузкой в виде нескольких файлов. Мой лимит составляет 40 КБ на загрузку. Поэтому, если пользователь загружает файл размером 400 КБ, он разделит этот файл на 10 отдельных фрагментов или 10 отдельных файлов во внешнем интерфейсе, прежде чем загружать его на сервер.
В настоящее время я делаю это, конвертируя этот файл в строку в формате base64, а затем разбиваю эту строку на 40 КБ, что дает 10 отдельных фрагментов. Оттуда я загружаю каждый фрагмент с именем файла chunk-1-of-10, chunk-2-of-10 ...
При извлечении этих файлов я просто объединяю все эти фрагменты и деконвертирую их из base64 в формат файла.
Есть ли лучший способ сделать это? Есть ли библиотека, которая обрабатывает все это вместо того, чтобы писать с нуля? Я не уверен, что маршрут base64 - лучший способ сделать это.
Вы можете избежать кодирования base64, используя FileReader
, а затем отправляя его в двоичном формате:
const url = 'http://www.example.com/upload';
document.getElementById('file-uploader').addEventListener('change', function(e) {
const size = 40000;
var reader = new FileReader();
var buf;
var file = document.getElementById('file-uploader').files[0];
reader.onload = function(e) {
buf = new Uint8Array(e.target.result);
for (var i = 0; i < buf.length; i += size) {
var fd = new FormData();
fd.append('fname', [file.name, i+1, 'of', buf.length].join('-'));
fd.append('data', new Blob([buf.subarray(i, i + size)]));
var oReq = new XMLHttpRequest();
oReq.open("POST", url, true);
oReq.onload = function (oEvent) {
// Uploaded.
};
oReq.send(fd);
}
}
reader.readAsArrayBuffer(file);
});
<input type = "file" id = "file-uploader"/>
Нет необходимости читать содержимое в оперативную память с помощью FileReader. использование base64 только увеличит размер того, что вам нужно загрузить
Используйте Blob.slice для получения чанков
// simulate a file from a input
const file = new File(['a'.repeat(1000000)], 'test.txt')
const chunkSize = 40000
const url = 'https://httpbin.org/post'
for (let start = 0; start < file.size; start += chunkSize) {
const chunk = file.slice(start, start + chunkSize + 1)
const fd = new FormData()
fd.append('data', chunk)
await fetch(url, {method: 'post', body: fd}).then(res => res.text())
}
Спасибо за решение! Одним из быстрых дополнений к этому было бы добавление «start» ко второму параметру slice () для получения последующих фрагментов. const chunk = file.slice (начало, начало + размер блока + 1).
Как нам вывести ответ сервера?
@ParsaYazdani console.info(await fetch(url, {method: 'post', body: fd}).then(res => res.text()))
У нас это сработало, однако нам пришлось внести небольшую корректировку, убрать +1 при вычислении чанка: const chunk = file.slice(start, start + chunkSize)
Как нам вывести ответ сервера?