当前位置:网站首页>大文件上传
大文件上传
2022-07-17 02:31:00 【Float544】
前端:
切片上传
1.格式校验
2.将文件解析为二进制ArrayBuffer数据。
3.利用二进制ArrayBuffer可以切割的属性,将二进制流进行切割。
4.组装和分割块同等数量的请求块,并行或串行的形式发出请求(本文使用串行)
5.待监听到所有请求都成功发出去后,给服务端发出合并请求(服务端合并文件成新文件,将保存hash切片的文件删除)
断点续传:
上传成功的切片客户端移除掉,上传失败的切片重新发送请求。
后端:
接收到每一个切割文件后,1.先进行multiparty解析,2.将切片存储到hash值命名的文件中 3.检查文件中是否存在当前切片(存在的话不再进行任何的处理 达到文件秒传的效果;不存在的话,将切片存入hash值命名的文件中)
接收到合并请求后。1.找到hash对应的文件夹 2.将所有的切片文件排序,合并,生成最终的大文件。3.删除切片文件夹 4.告知前端上传成功,并且发送文件url给前端。
async changeFile(file) {
//格式校验
let {
type } = file;
if (!/(png|gif|jpeg|jpg)/i.test(type)) {
this.$message("文件合适不正确~~");
return false;
}
//如果文件不存在,直接退出
if (!file) return;
file = file.raw;
// 我们会把文件切片处理:把一个文件分割成为好几个部分(固定数量/固定大小)
// 每一个切片有自己的部分数据和自己的名字
// HASH_1.mp4
// HASH_2.mp4
// ...
// 解析为ArrayBuffer数据
let buffer;
let fileRead = new FileReader()
fileRead.readAsArrayBuffer(file)
fileRead.onload = await(env)=>{
buffer = env.target.result
}
// 创建spark实例
spark = new SparkMD5.ArrayBuffer(),
hash,
suffix;
spark.append(buffer);
// 生成hash,文件名 根据spark-MD5生成的hash是由文件的内容决定的
hash = spark.end();
// 生成文件后缀名
suffix = /\.([0-9a-zA-Z]+)$/i.exec(file.name)[1];
// 创建100个切片
let partList = [],
partsize = file.size / 100,
cur = 0;
for (let i = 0; i < 100; i++) {
//每一个切片具有chunk(文件大小)和filename(文件名)属性
let item = {
chunk: file.slice(cur, cur + partsize),
filename: `${
hash}_${
i}.${
suffix}`,
};
cur += partsize;
partList.push(item);
}
this.partList = partList;
this.hash = hash;
//开始发送请求
this.sendRequest();
},
为每一个partList 中的切片创建一个axios请求
async sendRequest() {
// 根据100个切片创造100个请求(集合) requestList用来盛放100个切片请求
let requestList = [];
//开始为每一个切片生成请求
this.partList.forEach((item, index) => {
// 每一个函数都是发送一个切片的请求 基于文件流发送 Form-Data
let fn = () => {
let formData = new FormData();
formData.append("chunk", item.chunk);
formData.append("filename", item.filename);
return axios
.post("/single3", formData, {
headers: {
"Content-Type": "multipart/form-data" },
})
// 切片上传成功后删除切片,失败后重新发送请求上传
.then((result) => {
result = result.data;
if (result.code == 0) {
this.total += 1;
// 传完的切片我们把它移除掉 把没上传的留下 做到了断点续传
this.partList.splice(index, 1);
}
});
};
requestList.push(fn);
});
// 传递:串行(基于标志控制不发送)
// 传了多少
let i = 0;
// 开始合并 complete函数用于发送合并切片请求
let complete = async () => {
let result = await axios.get("/merge", {
params: {
// 将文件的hash作为标识,发送请求让后端进行合并
hash: this.hash,
},
});
result = result.data;
// 合并成功
if (result.code == 0) {
//客户端展示上传文件
this.video = result.path;
}
};
//开始发送请求
let send = async () => {
// 已经中断则不再上传
if (this.abort) return;
if (i >= requestList.length) {
// 都传完了 complete用于发送合并切片请求
complete();
return;
}
// 开始发送每个切片对应的请求
await requestList[i]();
i++;
send();
};
send();
},
边栏推荐
- Redis数据迁移:方法一RDB
- 让企业数字化砸锅和IT主管背锅的软件供应链安全风险指北
- Jmeter常用功能-参数化介绍
- [C language errata] error in getting array length in function
- EfficientNet系列(1): EfficientNetV2网络详解
- 【LeetCode】558. Intersection of quadtree
- 数学建模比赛论文模板格式
- 如何在自动化测试中使用MitmProxy获取数据返回?
- Sword finger offer 59 - ii Maximum value of queue
- Sparkcore core design: RDD, 220716,
猜你喜欢
随机推荐
No, check it out
How to paste data in Excel into CXGRID
SparkCore核心设计:RDD,220716,
2022长三角数学建模:齿轮箱故障诊断
Shorten the line width of tabs component
The role of key in V-for
[2016 CCPC Hangzhou j] just a math problem (Mobius inversion)
TS的使用案例——贪吃蛇
Introduction of modules (block, module)
如何在自动化测试中使用MitmProxy获取数据返回?
51单片机——双字节乘以双字节
go环境安装
Penetration test-01 information collection
时间轴组件
Animation 动画片段跳帧、动画队列
程序员生涯写过最大的Bug!网友:高低是个P8水平!
【LeetCode】346. Moving average in data flow
lc marathon 7.16
Qt OpenGL 通过鼠标和键盘移动三维物体(设置相机)
central limit theorem