2013-01-21 12 views
17

Ho un file lungo che devo analizzare. Perché è molto lungo ho bisogno di farlo pezzo di blocco. Ho provato questo:javascript FileReader - analisi di file lunghi in blocchi

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

Dopo averlo eseguito, vedo solo il primo blocco nella console. Se cambio 'console.log' in jquery append ad alcuni div, vedo solo il primo pezzo in quel div. Che ne dici di altri pezzi? Come farlo funzionare?

risposta

6

Il secondo argomento di slice è in realtà il byte finale. Il codice dovrebbe essere simile:

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

In alternativa è possibile utilizzare questo BlobReader per una più facile interfaccia:

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

Maggiori informazioni:

+0

Il loop è affidabile? Sono piuttosto nuovo all'API di FileReader, ma vedo che è asincrono. Come possiamo assicurarci che l'intero file sia stato elaborato completamente una volta terminato il ciclo 'for? – alediaferia

36

FileReader API è asincrono quindi è necessario gestirlo con le chiamate block. A for loop non farebbe il trucco dato che non aspetterebbe che ogni lettura fosse completata prima di leggere il prossimo blocco. Ecco un approccio di lavoro.

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's start the read with the first block 
    chunkReaderBlock(offset, chunkSize, file); 
} 
+2

Questo è geniale. Lettura di enormi file da 3 GB + senza problemi. La piccola dimensione del blocco lo rende un po 'lento. – bryc

+0

Ha scritto una calcolatrice CRC32 usando questo per divertimento usando web workers/dragndrop. http://jsfiddle.net/9xzf8qqj/ – bryc

+2

Ha funzionato anche per me per file di grandi dimensioni. Tuttavia, per i file più grandi (> 9 GB), ho scoperto incrementare 'offset' di' evt.target.result.length' era ** corrompendo ** il mio file! La mia soluzione rapida era invece di incrementarla con 'chunkSize'. Non sono sicuro che si tratti di un problema di FS (sono su Ubuntu) o qualcos'altro, ma funziona bene per qualsiasi dimensione di file se si esegue l'offset + = chunkSize'. – user40171

1

mi si avvicinò con un'idea molto interessante che è probabilmente molto veloce dato che convertirà il blob ad un ReadableByteStreamReader probabilmente molto più facile anche dal momento che non è necessario per gestire cose come dimensione del blocco e offset e poi fare tutto ricorsivo in un ciclo - ma funziona solo per Blink, Edge lo otterrà nella prossima versione

let pump = reader => reader.read() 
.then(({ value, done }) => { 
    if(done) return 
    console.log(value) // uint8array chunk 
    return pump(reader); 
}) 


window.blobToStream = blob => 
    fetch(URL.createObjectURL(blob)) 
    .then(res => pump(res.body.getReader())) 
Problemi correlati