断点续传:顾名思义,继续上次断开的点,继续上传。
思路整理:
- 拿到文件,对文件进行fingerprint = md5(file),得到文件指纹。
- 将指纹保存服务器。
- 切割文件,分段上传,每次上传一段。
- 服务器根据指纹进行索引判断文件上传进度,直到文件的全部片段上传完毕。
以下文字没有完整的代码,只有基础理论,伸手党绕道。
1. 读取文件
// 这里只演示单文件上传过程。
var input = document.querySelector('input');
input.addEventListener('change', function() {
var file = this.files[0];
//这里是有一个坑的,部分设备(华为部分机型)无法获取文件名称,和文件类型,这个在最后给出解决方案
var fileType = file.type;
// getFileType(file, fileType => {})
});
2. 获取文件指纹
var fingerprint = md5(file);
3. 文件切割
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.addEventListener("load", function(e) {
//每10M切割一段,这里只做一个切割演示,实际切割需要根据file.size进行循环切割.
let size = 1024 * 1024 * 10;
var slice = e.target.result.slice(0, size);
});
4. h5上传一个(一片)文件
// 一般情况下不需要getFileType。
getFileType(file, fileType => {
var formdata = new FormData();
formdata.append('fingerprint', fingerprint);
// 指纹作为文件名,并拼接文件类型(也可以在服务器断进行文件类型处理)
formdata.append('filename', fingerprint + '.' + fileType);
// 做好切片索引,把索引作为切片名称
// 第一片为了保存指纹,可以尽量切小一点。
formdata.append('0', slice);
var xhr = new XMLHttpRequest();
xhr.addEventListener('load', function () {
//xhr.responseText
});
xhr.open('POST', '');
xhr.send(formdata);
xhr.addEventListener('progress', updateProgress);
xhr.upload.addEventListener('progress', updateProgress);
});
function updateProgress(event) {
if (event.lengthComputable) {
//进度条
}
}
无法获取文件类型的设备解决方案
首先在:http://www.garykessler.net/li...查找对应文件的头信息
这里只给出了常见的图片和视频的文件类型判断
function getFileType(file, back) {
var name = file.name;
var type = '';
if (name) {
var lastIndex = name.lastIndex('.')
type = name.substring(lastIndex + 1)
back(type);
return;
}
// 如果系统无法获取文件类型,则读取二进制流,对二进制进行解析文件类型
var imgType = {
'ff d8 ff': 'jpg',
'89 50 4e': 'png',
'0 0 0 14 66 74 79 70 69 73 6F 6D': 'mp4',
'0 0 0 18 66 74 79 70 33 67 70 35': 'mp4',
'0 0 0 0 66 74 79 70 33 67 70 35': 'mp4',
'0 0 0 0 66 74 79 70 4D 53 4E 56': 'mp4',
'0 0 0 0 66 74 79 70 69 73 6F 6D': 'mp4',
'0 0 0 18 66 74 79 70 6D 70 34 32': 'm4v',
'0 0 0 0 66 74 79 70 6D 70 34 32': 'm4v',
'0 0 0 14 66 74 79 70 71 74 20 20': 'mov',
'0 0 0 0 66 74 79 70 71 74 20 20': 'mov',
'0 0 0 0 6D 6F 6F 76': 'mov',
'4F 67 67 53 0 02': 'ogg',
'1A 45 DF A3': 'ogg',
'52 49 46 46 x x x x 41 56 49 20': 'avi',
}
// 用最长的作为截取边界
var size = Object.keys(imgType).map(i => i.split(/\s+/).length).sort()[0]
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.addEventListener("load", function (e) {
var result = e.target.result
if (!result || result.length < size) {
back('')
return;
}
var slice = result.slice(0, size);
var view = new Uint8Array(slice);
var arr = view.map(v => v.toString(16))
type = imgType[arr.join(' ')];
if (!type) {
// 处理一个特殊情况:忽略第4-8位
arr = arr.map(function (v) {
if (i > 3 && i < 8) {
return 'x';
}
return v;
});
type = imgType[arr.join(' ')];
}
back(type);
});
}
总结:有了切割上传,有了文件唯一标识信息(文件md5)断点续传只不过是后台的一个小小的判断逻辑而已。
未来,前端,大有可为
有些小伙伴不是太清楚后台的小小的判断是怎么做的:
这里贴一张图给大家参考,自己手画,有点丑,将就下。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。