2015-02-07 62 views
0

我正在尝试使用FileReader API读取文件数据,并且阅读了很多与此相同问题的问题,并试图实现他们的解决方案,但对于我的代码中的一些错误(也许)继续做错误的结果。当文件太大(超过15MB)时,为了避免浏览器崩溃,我决定开始使用'slice'方法。但问题是,因为FileReader onload事件是异步的,所以我得到代码的一部分,它应该尽快完成缓冲区,但仍然不完整。而且我不能在onload事件中做所有的事情,因为它只有总缓冲区的一部分。这里是我的代码:完全等待FileReader slice blob

function readBlob(opt_startByte, opt_stopByte) 
{ 
    var file = window.files[0]; 
    var start = parseInt(opt_startByte) || 0; 
    var stop = parseInt(opt_stopByte) || file.size - 1; 

    var reader = new FileReader(); 

    // If we use onloadend, we need to check the readyState. 
    reader.onload = function(evt) {   
     window.bits.push(CryptoJS.AES.encrypt(evt.target.result, window.password)); 
    }; 
    var blob = file.slice(start, stop + 1); 
    reader.readAsDataURL(blob); 
} 

function encrypt() 
{ 
    window.files = document.getElementById('encrypt-input').files; 
    if (!window.files.length) { 
     alert('Please select a file!'); 
     return; 
    } 
    window.password = $('#key').val(); 
    window.bits = []; 
    var startByte = 0;    
    var endByte = 0; 
    while(startByte <= document.querySelector('input[type=file]').files[0].size - 1) 
    {  
     endByte = startByte + 1024; 
     readBlob(startByte, endByte); 
     startByte = endByte; 
     if (startByte >= document.querySelector('input[type=file]').files[0].size) 
     { 
      alert('Here I want the total array length:' + window.bits.length);  
     } 
    } 
      alert('Here I want the total array length:' + window.bits.length);   
} 

正如你所看到的正上方,我尝试这样做:

if (startByte >= document.querySelector('input[type=file]').files[0].size) 
    { 
     alert('Here I want the total array length:' + window.bits.length);  
    } 

但我仍然得到出于某种原因,长度为0。如何在使用slice方法时处理整个缓冲区?另一个次要问题是:在onload事件中,我调用了一个同步函数'CryptoJS.AES.encrypt',但由于这个事件是异步的,我期待浏览器在处理缓冲区时不会冻结到这个事件中。有没有什么办法可以实现某些功能,以避免在处理文件时冻结浏览器?

回答

0

发生这种情况的原因是reader.readAsDataURL()是异步的。你必须回调传递给readBlob它完成时被称为:

function readBlob(opt_startByte, opt_stopByte, done) { 
    ... 
    reader.onload = function(evt) {   
     window.bits.push(CryptoJS.AES.encrypt(evt.target.result, window.password)); 
     done(); 
    }; 
    ... 
} 

function encrypt() {  
    ... 
    var startByte = 0;    
    var endByte = 0; 
    var callback = function(){ 
     alert('Here I want the total array length:' + window.bits.length); 
    }; 
    while(startByte <= document.querySelector('input[type=file]').files[0].size - 1) { 
     endByte = startByte + 1024; 
     (function(startByte, endByte, newCallback){ 
      callback = function(){ 
       readBlob(startByte, endByte, newCallback); 
      }; 
     })(startByte, endByte, callback); 
     startByte = endByte; 
    } 
    callback(); // run the chain 
} 

我们根本没有其他合理的方式,因为JavaScript没有一个sleep功能。

+0

没有工作:(...如果我复制/粘贴你的例子,浏览器像无限循环冻结,如果我把'startByte = endByte'放在回调函数之外,它会被调用并每次向我显示警报onload被解雇了,不仅在完成时...看起来像是表达式不正确... – 2015-02-07 16:03:35

+0

是的,我不确定你想做什么,问题是有些执行是异步的, – 2015-02-07 16:26:29

+0

我的代码和你的完全一样,但readBlob永远不会被调用; \ ...这对我来说是一件奇怪的事情,因为API提供了一种切片方法,但对于一些原因是,我们无法通过简单的编码来达到完整的缓冲区,我认为这是一个正常的行为,它处理片中的文件,但是用完整的缓冲区执行一个函数,我不明白为什么这么做很难做到这点...... – 2015-02-07 16:45:26