2013-01-21 66 views
17

我有我需要解析的長文件。因爲它很長,我需要按塊來完成它。我試過這個: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附加到某個div,我只能看到該div中的第一個塊。其他大塊呢?如何使它工作?

回答

6

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

的更多信息:

+0

循環是否可靠?我對FileReader API比較陌生,但我發現它是異步的。我們如何確保整個文件在「for循環」結束後都被完全處理? – alediaferia

36

FileReader API是異步的,因此您應該使用block調用來處理它。一個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's start the read with the first block 
    chunkReaderBlock(offset, chunkSize, file); 
} 
+2

這太棒了。閱讀巨大的3GB +文件沒有問題。小塊大小使它有點慢。 – bryc

+0

使用此工具編寫了一個CRC32計算器,以便使用網絡工作者/ dragndrop獲得樂趣。 http://jsfiddle.net/9xzf8qqj/ – bryc

+2

爲我工作,以及大型文件。然而,對於較大的文件(> 9GB),我發現通過'evt.target.result.length'遞增'offset'會導致**文件損壞!我的快速解決方案是通過'chunkSize'來增加它。我不確定它是否是FS問題(我在Ubuntu上)或其他東西,但是如果您偏移了+ = chunkSize,它對任何文件大小都可以。 – user40171

1

我想出了一個非常有趣的想法,可能是非常快的,因爲它會團塊轉換爲ReadableByteStreamReader太多可能比較容易,因爲你並不需要處理的東西像塊大小和偏移量,然後做它都是循環遞歸 - 但只適用於Blink,Edge會在下一個版本中使用

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()))