今天主要讲讲文件切片,主要在上传大文件的时候需要用到,你想想,上传一个几百兆的大视频,但网络带宽又特别感人,一个不小心就报错造成上传失败,那是什么感受...
进入正题,选择文件后,点击“确定”,首先计算出文件总大小,然后需要做什么呢,你需要告诉服务器这个大文件被切成了多少片,还得在每次上传的时候告诉它当前是第几片。最好加一个Date.now(),不然大家同时上传一个1.jpg,一到服务器就重名了,加了Date.now(),1_(时间戳).jpg就不会重名了。
每次上传的Blob对象使用file.slice(start, end)完成:
注意红框标注的地方,每次上传都需要执行formData['delete'](fileName),至于原因已经在里面加入了,自己看哈。
下面是上传进度和上传速度的代码:
var xhr = ZUtil.getXHR(),
formData = new FormData(),
// 上次的时间戳
prev = new Date().getTime(),
// 以上传
load = 0,
// 文件大小
size = file.size,
translateSize = ZUtil.translateByte(size),
prevProgress = 0,
$bar = $row.find('.z-progress-bar'),
$progress = $row.find('.z-upload-progress'),
$speed = $row.find('.z-upload-speed'),
$progressLinear = $row.find('.z-upload-progress-linear');
formData.append('uniqueFlag', Date.now());
formData.append('fileName', file.name);
xhr.addEventListener('error', uploadError, false);
xhr.upload.addEventListener('progress', function(e) {
// e.loaded是本次请求已经上传的文件大小
var loaded,
// 当前时间戳
now = new Date().getTime(),
distance = now - prev;
if (splitUpload) {
/*** 如果是分片上传,e.loaded是每次的file.slice(start, end),理论上就是每份文件切片大小* 而不会像整体文件上传一样,e.loaded是从0慢慢增长到file.size* 需要加上load才是已经上传的文件大小*/loaded = e.loaded + load;
} else {
loaded = e.loaded;
}
var progress = Math.min(Math.round(loaded / size * 100), 100);
/**
* 每次更新的时间间隔 >= speedUpdateInterval
* 或者上传完毕(如果是分片上传,那么e.loaded >= splitSize也意味着当前分片文件上传完成)
*/
if(distance >= speedUpdateInterval || (progress == 100 || (splitUpload && e.loaded >= splitSize))) {
var speed = ZUtil.translateByte((loaded - load) / distance * 1000);$speed.html('速度:' + speed + '/s');prev = now;load = loaded;
}
if(progress != prevProgress) {
prevProgress = progress;$progress.html('进度:' + progress + '% of ' + translateSize);$progressLinear.css({
width : progress + '%'
});
}
下面是文件上传效果:
第一个切片:
最后一个切片:
大家也看到了,文件只有216KB,我设置的切片大小只有0.01MB,所以才会上传22次。
onreadystatechange代码
可以看到,每次需要后端返回success,并且当前切片index < 总切片数totalIndex才会继续上传,如果全部上传完毕,会调用afterUpload回调方法
后端java代码
通过对比index和totalIndex,如果相同,就合并文件。
上一篇已经提过如果不适用切片,仅仅一个进度条,这都是骗人的。使用切片后,分片上传文件,等到上一片文件上传成功后才会继续上传下一片,因为公司没有要求使用数据库记录切片信息,所以每次上传切片后没有将切片文件信息保存到数据库,要是哪个切片上传失败了,只能重新上传...这样做虽然花费的时间长了一点(当然了,这么多次请求,HTTP握手肯定很费时间的),不过这样也是值得的,几百兆的大文件重复上传更费时间呢,反正还是需要开发者自己权衡,个人建议,几兆的小文件就别用切片了,麻烦。