用HTML5实现断点续传、上传进度条、图片预览 【2】
用HTML5实现断点续传、上传进度条、图片预览 【2】 · Oct 10, 2014 clicks
在上一篇文章中,已经基本实现了文件上传的所有功能,还遗留了2个问题:一是计算文件hash时一次性读取了文件内容,存在内存限制; 二是只实现了单文件上传
事实上,Spark MD5给出了分片读取文件,计算md5值的过程。
照着那个例子,把代码重新修改了下
<!doctype html> <html> <head> <title>Upload File via XMLHttpRequest 2</title> <script src="spark_md5.min.js"></script> <script> var fr_supported = typeof FileReader != 'undefined'; var fd_supported = typeof FormData != 'undefined'; if ( !fr_supported ){ alert('you browser doesnt support FileReader!'); } if ( !fd_supported ){ alert('you browser doesnt support FormData!'); } function get(id){ return document.getElementById(id); } var pos = 0; var slice_size = 1024 * 1024; var upload_data=null; var upload_finished = false; var upload_file_size = 0; var upload_file = null; var upload_file_hash= ''; function fileSelected(){ var file = get('fileToUpload').files[0]; upload_file = file; pos = 0; upload_data = null ; upload_finished = false; upload_file_hash = ''; if ( file ){ upload_file_size = file.size; var fileSize = 0; if (file.size > 1024*1024){ fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB'; }else{ fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB'; } get('fileName').innerHTML = file.name; get('fileSize').innerHTML = fileSize; get('fileType').innerHTML = file.type; //preview image if ( file.type.split('/')[0] == 'image' ){ var rd = new FileReader(); rd.addEventListener('load',function(evt){ var im = new Image(); im.src = evt.target.result; get('preview').innerHTML = ''; get('preview').appendChild(im); },false); rd.readAsDataURL(file); } } } function checkFileMd5(file,callback) { var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice; var chunk_size = 1024 * 1024 *10; //10M var current_chunk = 0; var chunk_count = Math.ceil(file.size / chunk_size); var spark = new SparkMD5.ArrayBuffer(); var rd = new FileReader(); rd.addEventListener('load',function(evt){ spark.append(evt.target.result); current_chunk ++; if (current_chunk < chunk_count){ loadNext(); }else{ callback(file, spark.end() ); } }); rd.addEventListener('error',function(evt){ console.log(['err ocurs while computing hash']); }) function loadNext(){ var start = current_chunk * chunk_size, end = ((start+chunk_size)>=file.size) ? file.size : start+chunk_size; rd.readAsArrayBuffer(blobSlice.call(file,start,end)) }; loadNext(); } function uploadFile() { var file = upload_file; //get md5 hash checkFileMd5(file,afterCheckhash); } function afterCheckhash(file,hash_val) { upload_file_hash = hash_val; //console.log(['md5', upload_file_hash ]); //get size of uploaded data var xhr = new XMLHttpRequest(); var fd = new FormData(); fd.append('act','query'); fd.append('qry_fname', file.name ); fd.append('file_hash', upload_file_hash); xhr.addEventListener('load',function(stat){ pos = parseInt(this.responseText); //console.log([upload_file,pos,upload_file_size]); if ( pos < upload_file_size){ upload_data = upload_file.slice(pos, pos+slice_size); upload_finished = (pos + slice_size) >= upload_file_size; get('progressNumber').innerHTML = Math.round(pos*100/upload_file_size)+'%'; //upload file do_upload_file(); }else{ upload_finished = true; get('progressNumber').innerHTML = '100%'; alert('file already upladed'); } },false); xhr.open("POST",'upload.php'); xhr.send(fd); } function do_upload_file(){ if ( upload_data==null ){ alert( 'nothing to upload' ); return; } var xhr = new XMLHttpRequest(); var fd = new FormData(); fd.append('act','upload'); fd.append('uploadfile', upload_data ); fd.append('filename', upload_file.name); fd.append('finished', upload_finished?'1':'0' ); fd.append('position', pos); fd.append('file_hash', upload_file_hash); xhr.upload.addEventListener("progress", uploadProgress,false); xhr.addEventListener("load", uploadComplete,false); xhr.addEventListener("error", uploadFailed,false); xhr.addEventListener("abort", uploadCanceled, false); xhr.open("POST", "upload.php"); xhr.send(fd); } function uploadProgress(evt){ var percent = 'unable to compute progress'; if (evt.lengthComputable){ var percent = Math.round( (evt.loaded+pos)*100/upload_file_size ) + '%'; } get('progressNumber').innerHTML = percent; } function uploadComplete(evt){ //alert( evt.target.responseText ); //console.log([evt.target.responseText]); if ( !upload_finished ){ pos += slice_size; upload_data = upload_file.slice(pos, pos+slice_size); upload_finished = (pos + slice_size) >= upload_file_size; do_upload_file(); } } function uploadFailed(evt){ alert('Failed to upload'); } function uploadCanceled(evt){ alert('the upload has been canceled'); } </script> <body> <form action="upload.php" id="form1" method="post" enctype="multipart/form-data"> <div class="row"> <label for="fileToUpload">Select a File to Upload</label> <br /> <input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected()" /> </div> <p>FileName: <span id="fileName"></span></p> <p>FileSize: <span id="fileSize"></span></p> <p>FileType: <span id="fileType"></span></p> <p id="preview"></p> <div class="row"> <input type="button" onclick="uploadFile()" value="Upload" /> </div> <p>Progress: <span id="progressNumber"></span></p> </form>