2013-11-26 5 views
7

は次のとおりです。スライス大きなファイルとAjaxを使用してアップロードして、HTML5 FileReaderの私が実装したい何

フロントエンドで、私は、ファイルを読むためにHTML5ファイルAPIを使用し、その後に、ファイルのコンテンツをアップロードPHPのバックエンドはajaxを使用しており、ファイルサイズが小さい場合は問題ありません。しかし、ファイルが十分に大きければ、クロムがクラッシュします。だから私は大量のファイルをfile.sliceを使ってチャンクに分割し、すべてのチャンクがPHPにアップロードされ、チャンクを1つの完全なものにマージします。次のように

コードは次のとおりです。

フロントエンド:

<style> 
#container { 
    min-width:300px; 
    min-height:200px; 
    border:3px dashed #000; 
} 
</style> 
<div id='container'> 

</div> 
<script> 
function addDNDListener(obj){ 
    obj.addEventListener('dragover',function(e){ 
      e.preventDefault(); 
      e.stopPropagation(); 
    },false); 
    obj.addEventListener('dragenter',function(e){ 
      e.preventDefault(); 
      e.stopPropagation(); 
    },false); 
    obj.addEventListener('drop',function(e){ 
      e.preventDefault(); 
      e.stopPropagation(); 
      var ul = document.createElement("ul"); 
      var filelist = e.dataTransfer.files; 
      for(var i=0;i<filelist.length;i++){ 
        var file = filelist[i]; 
        var li = document.createElement('li'); 
        li.innerHTML = '<label id="'+file.name+'">'+file.name+':</label> <progress value="0" max="100"></progress>'; 
        ul.appendChild(li); 
      } 
      document.getElementById('container').appendChild(ul); 
      for(var i=0;i<filelist.length;i++){ 
        var file = filelist[i]; 
        uploadFile(file); 
      } 
    },false); 
} 

function uploadFile(file){ 
    var loaded = 0; 
    var step = 1024*1024; 
    var total = file.size; 
    var start = 0; 
    var progress = document.getElementById(file.name).nextSibling; 

    var reader = new FileReader(); 

    reader.onprogress = function(e){ 
      loaded += e.loaded; 
      progress.value = (loaded/total) * 100; 
    }; 

    reader.onload = function(e){ 
      var xhr = new XMLHttpRequest(); 
      var upload = xhr.upload; 
      upload.addEventListener('load',function(){ 
        if(loaded <= total){ 
          blob = file.slice(loaded,loaded+step+1); 
          reader.readAsBinaryString(blob); 
        }else{ 
          loaded = total; 
        } 
      },false); 
      xhr.open("POST", "upload.php?fileName="+file.name+"&nocache="+new Date().getTime()); 
      xhr.overrideMimeType("application/octet-stream"); 
      xhr.sendAsBinary(e.target.result); 
    }; 
    var blob = file.slice(start,start+step+1); 
    reader.readAsBinaryString(blob); 
} 

window.onload = function(){ 

    addDNDListener(document.getElementById('container')); 
    if(!XMLHttpRequest.prototype.sendAsBinary){ 
       XMLHttpRequest.prototype.sendAsBinary = function(datastr) { 
         function byteValue(x) { 
          return x.charCodeAt(0) & 0xff; 
         } 
         var ords = Array.prototype.map.call(datastr, byteValue); 
         var ui8a = new Uint8Array(ords); 
         try{ 
          this.send(ui8a); 
         }catch(e){ 
          this.send(ui8a.buffer); 
         } 
       }; 
    } 
}; 
</script> 

PHPコード:

<?php 
    $filename = "upload/".$_GET['fileName']; 
    //$filename = "upload/".$_GET['fileName']."_".$_GET['nocache']; 
    $xmlstr = $GLOBALS['HTTP_RAW_POST_DATA']; 
    if(empty($xmlstr)){ 
      $xmlstr = file_get_contents('php://input'); 
    } 
    $is_ok = false; 
    while(!$is_ok){ 
      $file = fopen($filename,"ab"); 

      if(flock($file,LOCK_EX)){ 
        fwrite($file,$xmlstr); 
        flock($file,LOCK_UN); 
        fclose($file); 
        $is_ok = true; 
      }else{ 
        fclose($file); 
        sleep(3); 
      } 
    } 

ファイルのチャンクがすべてにアップロードされた後に問題があり、新しいファイルにマージした場合、ファイルサイズの合計が元のファイルサイズよりも小さくなり、マージされたファイルが破損します。問題はどこにあり、どのように修正するのですか?

+0

である可能性があります。それを何度も繰り返し、出現するパターンを探します。 – Achshar

+0

http://kongaraju.blogspot.in/2012/07/large-file-upload-more-than-1gb-using.html問題がまだ存在する場合はこれを試してください –

答えて

0

この問題は、主に共有ホストのグローバルな制限が原因で発生します。彼らはしばしばデータの量を制御し、制限が上書きされた場合にConnectionを削除します。 私はこれを数回試しました。常に同じ位置にくっついている。ターゲットファイルが小さくて破損していました。このサイズよりもアップロードするファイルが小さくても、マージされたデータが限界に収まるように、結果はOKでした。 チャンスが1つしかありません:ファイルを開くには、最大サイズを大きくしてください。 ターゲットファイルを開いてチャンクの内容を書き込むたびに、サイズが制限を上書きすると、ホストがConnectionを切断します。例hoster:Strato ここでは、Limitは全体的に16MBに設定されています。このサイズの2倍のマージ結果サイズが得られます。それを無効にするチャンスはありません。

3

あなたのjsスクリプト に小さなエラーがあり、私はreader.onprogressイベントがXHR 負荷イベントよりも多くの時間を引き起こしていることに気づきました。この場合、一部のチャンクはスキップされます。 にロードし、の負荷の内部に変数を増やしてみてください。

function uploadFile(file){ 
var loaded = 0; 
var step = 1024*1024; 
var total = file.size; 
var start = 0; 
var progress = document.getElementById(file.name).nextSibling.nextSibling; 

var reader = new FileReader(); 

reader.onload = function(e){ 
     var xhr = new XMLHttpRequest(); 
     var upload = xhr.upload; 
     upload.addEventListener('load',function(){ 
     loaded += step; 
     progress.value = (loaded/total) * 100; 
       if(loaded <= total){ 
         blob = file.slice(loaded,loaded+step); 

         reader.readAsBinaryString(blob); 
       }else{ 
         loaded = total; 
       } 
     },false); 
     xhr.open("POST", "upload.php?fileName="+file.name+"&nocache="+new Date().getTime()); 
     xhr.overrideMimeType("application/octet-stream"); 
     xhr.sendAsBinary(e.target.result); 
}; 
var blob = file.slice(start,step); 
reader.readAsBinaryString(blob); } 
3
  • についてはこちらをご参照くださいreadAsBinaryString fnはちょうど悪い習慣です
  • を使用SendAsBinaryもチャンクの内容は単なる純粋DUMで読む
  • を廃止予定されています。スライスするだけで十分です。
  • 誰もが大きなファイルをアップロードするためのワーカースレッド、BASE64またはFileReaderのを使用する方法についてスマートにしようとした場合、サーバはそう(なDropboxの限られたRESTのAPIなど)などの大容量ファイル
  • に同意しない場合を除きスライスも不要です - ドン」それはすべて不要です。

ファイルを読み取ったりスライスしたりするときは、ファイルを暗号化/復号化/圧縮してからサーバーに送信することを決定する必要があります。
ただし、すべてのブラウザがストリームをサポートし始めるまでの期間は限られています。
は、その後、あなたは見てみる必要がありますあなただけのただやる、サーバーへのブロブを転送する必要がある場合は、フェッチとReadableStream

fetch(url, {method: 'post', body: new ReadableStream({...})}) 

xhr.send(blob_or_file)とブラウザが正しく(それを読んでの世話をします)、メモリを消費しません。ファイルは大規模になる可能性がありますが、ファイル/ BLOBは

関連する問題