用HTML5实现断点续传、上传进度条、图片预览 【2】

用HTML5实现断点续传、上传进度条、图片预览 【2】 · Oct 10, 2014 404 clicks

上一篇文章中,已经基本实现了文件上传的所有功能,还遗留了2个问题:一是计算文件hash时一次性读取了文件内容,存在内存限制; 二是只实现了单文件上传

事实上,Spark MD5给出了分片读取文件,计算md5值的过程。

照着那个例子,把代码重新修改了下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
<!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>