2014-09-12 36 views
24

Il mio codice api del lettore di file ha funzionato bene fino a quando un giorno ho ricevuto un file txt da 280MB da uno dei miei clienti. La pagina si arresta immediatamente in Chrome e in Firefox non succede nulla.file-filereader api su file di grandi dimensioni

// create new reader object 
var fileReader = new FileReader(); 

// read the file as text 
fileReader.readAsText($files[i]); 
fileReader.onload = function(e) 
{ // read all the information about the file 
    // do sanity checks here etc... 
    $timeout(function() 
    {  
     // var fileContent = e.target.result; 
     // get the first line 
     var firstLine = e.target.result.slice(0, e.target.result.indexOf("\n")); }} 

Quello che sto cercando di fare in precedenza è che ottenere la prima interruzione di riga in modo che posso ottenere la lunghezza della colonna del file. Non dovrei leggerlo come testo? Come posso ottenere la lunghezza della colonna del file senza rompere la pagina su file di grandi dimensioni?

risposta

46

L'applicazione non funziona correttamente per i file di grandi dimensioni poiché si sta leggendo il file completo in memoria prima di elaborarlo. Questa inefficienza può essere risolta eseguendo lo streaming del file (leggendo blocchi di piccole dimensioni), quindi è sufficiente conservare una parte del file in memoria.

A oggetti File è anche un'istanza di Blob, che offre il metodo .slice per creare una vista più piccola del file.

Ecco un esempio che presuppone che l'input sia ASCII (demo: http://jsfiddle.net/mw99v8d4/).

function findColumnLength(file, callback) { 
    // 1 KB at a time, because we expect that the column will probably small. 
    var CHUNK_SIZE = 1024; 
    var offset = 0; 
    var fr = new FileReader(); 
    fr.onload = function() { 
     var view = new Uint8Array(fr.result); 
     for (var i = 0; i < view.length; ++i) { 
      if (view[i] === 10 || view[i] === 13) { 
       // \n = 10 and \r = 13 
       // column length = offset + position of \r or \n 
       callback(offset + i); 
       return; 
      } 
     } 
     // \r or \n not found, continue seeking. 
     offset += CHUNK_SIZE; 
     seek(); 
    }; 
    fr.onerror = function() { 
     // Cannot read file... Do something, e.g. assume column size = 0. 
     callback(0); 
    }; 
    seek(); 

    function seek() { 
     if (offset >= file.size) { 
      // No \r or \n found. The column size is equal to the full 
      // file size 
      callback(file.size); 
      return; 
     } 
     var slice = file.slice(offset, offset + CHUNK_SIZE); 
     fr.readAsArrayBuffer(slice); 
    } 
} 

Il snippet precedente conta il numero di byte prima dell'interruzione di riga. Il conteggio del numero di caratteri in un testo composto da caratteri multibyte è leggermente più difficile, poiché è necessario tenere conto della possibilità che l'ultimo byte nel blocco possa essere una parte di un carattere multibyte.

+2

Sei ufficialmente il mio eroe. All'inizio, avevo la stessa idea di leggerlo come un pezzo di blob invece di leggere il tutto ma non ne sapevo abbastanza per farlo funzionare. Non hai idea di quanto apprezzo questo. Grazie! – ODelibalta

+0

Cosa consiglieresti se dovessi determinare l'ultimo blocco nel file? Il sistema con cui sto lavorando ha una API REST diversa per l'ultimo chunk che poi impegna l'intero file. Ma non riesco a capire come determinare quell'ultimo pezzo. Se non ti dispiacerebbe guardare la mia domanda che sarebbe utile http://stackoverflow.com/questions/39312451/determining-the-last-file-chunk/39312577#39312577 – Batman

+1

Mi chiedo come posso usare questo per [ leggi 'n' linee da un grande file] (http://stackoverflow.com/questions/39479090/read-n-lines-of-a-big-text-file) .....:/ – gsamaras