用HTML5实现断点续传、上传进度条、图片预览 【2】
用HTML5实现断点续传、上传进度条、图片预览 【2】 · October 10, 2014 views: 221
在上一篇文章中,已经基本实现了文件上传的所有功能,还遗留了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>