Javascript FileReader - анализ длинного файла в кусках

У меня есть длинный файл, который мне нужно проанализировать. Потому что очень долго мне нужно сделать это куском куска. Я пробовал это:

function parseFile(file){
 var chunkSize = 2000;
 var fileSize = (file.size - 1);
 var foo = function(e){
 console.log(e.target.result);
 };
 for(var i =0; i < fileSize; i += chunkSize)
 {
 (function( fil, start ) {
 var reader = new FileReader();
 var blob = fil.slice(start, chunkSize + 1);
 reader.onload = foo;
 reader.readAsText(blob);
 })( file, i );
 }
}

После запуска я вижу только первый фрагмент в консоли. Если я изменил "console.log" на jquery append на некоторый div, я вижу только первый фрагмент в этом div. А как насчет других кусков? Как заставить его работать?

3 ответа

FileReader API является асинхронным, поэтому вы должны обрабатывать его с помощью вызовов block. A for loop не будет делать трюк, так как он не дождался завершения каждого чтения перед чтением следующего фрагмента. Здесь рабочий подход.

function parseFile(file, callback) {
 var fileSize = file.size;
 var chunkSize = 64 * 1024; // bytes
 var offset = 0;
 var self = this; // we need a reference to the current object
 var chunkReaderBlock = null;
 var readEventHandler = function(evt) {
 if (evt.target.error == null) {
 offset += evt.target.result.length;
 callback(evt.target.result); // callback for handling read chunk
 } else {
 console.log("Read error: " + evt.target.error);
 return;
 }
 if (offset >= fileSize) {
 console.log("Done reading file");
 return;
 }
 // of to the next chunk
 chunkReaderBlock(offset, chunkSize, file);
 }
 chunkReaderBlock = function(_offset, length, _file) {
 var r = new FileReader();
 var blob = _file.slice(_offset, length + _offset);
 r.onload = readEventHandler;
 r.readAsText(blob);
 }
 // now let start the read with the first block
 chunkReaderBlock(offset, chunkSize, file);
}


Второй аргумент slice на самом деле является конечным байтом. Ваш код должен выглядеть примерно так:

function parseFile(file){
 var chunkSize = 2000;
 var fileSize = (file.size - 1);
 var foo = function(e){
 console.log(e.target.result);
 };
 for(var i =0; i < fileSize; i += chunkSize) {
 (function( fil, start ) {
 var reader = new FileReader();
 var blob = fil.slice(start, chunkSize + start);
 reader.onload = foo;
 reader.readAsText(blob);
 })(file, i);
 }
}

Или вы можете использовать этот BlobReader для упрощения интерфейса:

BlobReader(blob)
.readText(function (text) {
 console.log('The text in the blob is', text);
});

Дополнительная информация:


Я придумал очень интересный idéa, который, вероятно, очень быстрый, так как он преобразует blob в ReadableByteStreamReader, вероятно, намного проще, так как вам не нужно обрабатывать такие вещи, как размер и смещение куска, а затем делать все рекурсивные цикл - но работает только для Blink, Edge получит его в следующей версии

let pump = reader => reader.read()
.then(({ value, done }) => {
 if(done) return
 console.log(value) // ********** chunk
 return pump(reader);
})
window.blobToStream = blob =>
 fetch(URL.createObjectURL(blob))
 .then(res => pump(res.body.getReader()))

licensed under cc by-sa 3.0 with attribution.