大文件分片上传

大文件分片上传,主要是为了提高上传效率,避免网络问题或者其他原因导致整个上传失败。

HTML部分没什么特殊代码,这里只写js代码。用原生js实现,框架中可参考实现

常规版本

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
// 获取上传文件的 input框
const ipt = document.querySelector("input")

ipt.onchange = async (e) => {
// 拿到文件
const file = e.target.files[0];
if (!file) {
return
}
// 通过 cutFile函数,拿到切片后的数据结果
cutFile(file).then(res => {
// res 是一个 切片后的结果数组
// 用来上传后端
// res 数据结构大概是这样

// [
// {
// blob: Blob, // 分片文件数据
// end: 22222, // 当前分片的截止位置
// hash: 121212122dasd // 当前分片的hash值,用来确认哪些片段已经上传,哪些上传失败好重新上传
// index: 0, // 当前分片的索引(在所有分片中的位置)
// start: 0, // 当前分片的起始位置
// }
// ]
})
}

// 定义 cutFile 函数
const CHUNK_SIZE = 1 * 1024 * 1024; // 每一片文件的大小 这里暂定 每片 1MB
async function cutFile(file) {
let res = [];
let chunkCount = Math.ceil(file.size / CHUNK_SIZE); // 向上取整,即 即算出来 5.5片 就取 6片
for (let i = 0; i < chunkCount; i++) {
let chunk = await createChunks(file, i, CHUNK_SIZE)
res.push(chunk);
}
return res;
}


// 创建分片辅助函数
function createChunks (file, index, chunkSize) {
return new Promise((resolve) => {
const start = index * chunkSize;
const end = start + chunkSize; // 注意边界问题
const spark = new SparkMD5(); // 用来生成文件hash,需要安装 spark-md5
const fileReader = new FileReader();
const blob = file.slice(start, end);
fileReader.onload = e => {
spark.append(e.target.result)
resolve({
start,
end,
blob,
hash: spark.end(), // 这一步是同步任务,很耗时,如果分片很多,请考虑使用web worker开启多线程进行
index
});
}
fileReader.readAsArrayBuffer(blob)

});
}

大致思路如上,可能有些细节在使用时需要自己调整