首页 > 其他分享 >如何实现大文件上传

如何实现大文件上传

时间:2023-10-07 14:24:11浏览次数:34  
标签:文件 请求 切片 如何 file chunkList 上传

一、解决方案
既然大文件上传不适合一次性上传,那么将文件分片散上传是不是就能减少性能消耗了。

分片上传就是将大文件分成一个个小文件(切片),将切片进行上传,等到后端接收到所有切片,再将切片合并成大文件。通过将大文件拆分成多个小文件进行上传,确实就是解决了大文件上传的问题。因为请求时可以并发执行的,这样的话每个请求时间就会缩短,如果某个请求发送失败,也不需要全部重新发送。

二、具体实现
(1)读取文件
准备HTML结构,包括:读取本地文件(input类型为file)、上传文件按钮、上传进度。

<input type="file" id="input">
<button id="upload">上传</button>
<!-- 上传进度 -->
<div style="width: 300px" id="progress"></div>
JS实现文件读取:

监听input的change事件,当选取了本地文件后,打印事件源可得到文件的一些信息:

let input = document.getElementById('input')
let upload = document.getElementById('upload')
let files = {}//创建一个文件对象
let chunkList = []//存放切片的数组

// 读取文件
input.addEventListener('change', (e) => {
files = e.target.files[0]
console.log(files);

//创建切片
//上传切片
})

(2)创建切片
文件的信息包括文件的名字,文件的大小,文件的类型等信息,接下来可以根据文件的大小来进行切片,例如将文件按照1MB或者2MB等大小进行切片操作:

// 创建切片
function createChunk(file, size = 2 * 1024 * 1024) {//两个形参:file是大文件,size是切片的大小
const chunkList = []
let cur = 0
while (cur < file.size) {
chunkList.push({
file: file.slice(cur, cur + size)//使用slice()进行切片
})
cur += size
}
return chunkList
}

切片的核心思想是:创建一个空的切片列表数组chunkList,将大文件按照每个切片2MB进行切片操作,这里使用的是数组的Array.prototype.slice()方法,那么每个切片都应该在2MB大小左右,如过文件的大小是8359021,那么可得到4个切片,分别是[0,2MB]、[2MB,4MB]、[4MB,6MB]、[6MB,8MB]。调用createChunk函数,会返回一个切片列表数组,实际上,有几个切片就相当于有几个请求。

调用创建切片函数:

//注意调用位置,不是在全局,而是在读取文件的回调里调用
chunkList = createChunk(files)
console.log(chunkList);
(3)上传切片
上传切片的个关键的操作:

第一、数据处理。需要将切片的数据进行维护成一个包括该文件,文件名,切片名的对象,所以采用FormData对象来进行整理数据。FormData 对象用以将数据编译成键值对,可用于发送带键数据,通过调用它的append()方法来添加字段,FormData.append()方法会将字段类型为数字类型的转换成字符串(字段类型可以是 Blob、File或者字符串:如果它的字段类型不是 Blob 也不是 File,则会被转换成字符串类。

第二、并发请求。每一个切片都分别作为一个请求,只有当这4个切片都传输给后端了,即四个请求都成功发起,才上传成功,使用Promise.all()保证所有的切片都已经传输给后端。

//数据处理
async function uploadFile(list) {
const requestList = list.map(({file,fileName,index,chunkName}) => {
const formData = new FormData() // 创建表单类型数据
formData.append('file', file)//该文件
formData.append('fileName', fileName)//文件名
formData.append('chunkName', chunkName)//切片名
return {formData,index}
})
.map(({formData,index}) =>axiosRequest({
method: 'post',
url: 'http://localhost:3000/upload',//请求接口,要与后端一一一对应
data: formData
})
.then(res => {
console.log(res);
//显示每个切片上传进度
let p = document.createElement('p')
p.innerHTML = `${list[index].chunkName}--${res.data.message}`
document.getElementById('progress').appendChild(p)
})
)
await Promise.all(requestList)//保证所有的切片都已经传输完毕
}

//请求函数
function axiosRequest({method = "post",url,data}) {
return new Promise((resolve, reject) => {
const config = {//设置请求头
headers: 'Content-Type:application/x-www-form-urlencoded',
}
//默认是post请求,可更改
axios[method](url,data,config).then((res) => {
resolve(res)
})
})
}

// 文件上传
upload.addEventListener('click', () => {
const uploadList = chunkList.map(({file}, index) => ({
file,
size: file.size,
percent: 0,
chunkName: `${files.name}-${index}`,
fileName: files.name,
index
}))
//发请求,调用函数
uploadFile(uploadList)

})

 

参考文章:http://blog.ncmem.com/wordpress/2023/10/07/%e5%a6%82%e4%bd%95%e5%ae%9e%e7%8e%b0%e5%a4%a7%e6%96%87%e4%bb%b6%e4%b8%8a%e4%bc%a0/

欢迎入群一起讨论

 

标签:文件,请求,切片,如何,file,chunkList,上传
From: https://www.cnblogs.com/songsu/p/17746174.html

相关文章

  • 删除/etc/fstab文件中所有以#开头,后面至少跟一个空白字符的行的行首的#和空白字符
    [16:36:16root@centos8~]#cat-A/etc/fstab$#$#/etc/fstab$#CreatedbyanacondaonMonJul1912:39:262021$#$#Accessiblefilesystems,byreference,aremaintainedunder'/dev/disk/'.$#Seemanpagesfstab(5),findfs(8),mount(8)and/orblkid(......
  • 如何处理一类多区间问题
    形如\(\sum_{i=l}^rM(L+i,R+i,x)\)一类问题不难发现这个东西实际上就是一堆等差数列,考虑这样高维差分我们在\(i\)处放一个1,就相当于在这里生成了一个公差为1等差数列,先在\(L+l\)处生成一个数列111111111111111111111 111111111 ......
  • java中如何对特大文件做断点续传RandomAccessFile
    Java中可以使用 RandomAccessFile 类来实现特大文件的断点续传功能。importjava.io.File;importjava.io.IOException;importjava.io.RandomAccessFile;importjava.net.URL;importjava.net.HttpURLConnection;publicclassResumeDownloadExample{publicstaticvoi......
  • 如何科学地分析高中学生成绩
    科学地分析高中学生成绩需要综合考虑多个因素,包括学生个人素质、学习方法、学校教育环境等。以下是一个详细的分析过程,供参考:一、学生个人素质分析:1.学习态度和动机:分析学生对学习的态度和动机是否积极主动,是否具有持之以恒的学习动力以及是否具备学习的目标感。2.自我管理......
  • 为功耗分析生成仿真波形文件及RTL文件列表
    一、获取RTL文件列表RTL文件包括vhdl,v,sv三种文件,可以根据后缀获取工程内部所有文件夹,及子文件夹内部的相关文件。可以通过shell脚本实现该功能。1#!/bin/bash2######################################################################3##......
  • Python简易HTTP文件服务器
    我超怕的-HTTPsimplefileserverusePython-https://www.cnblogs.com/iAmSoScArEd/p/17745959.htmlHowtouse安装依赖:pip3installflask保存到文本simple_file_server.py后运行:python3simple_file_server.py浏览器访问:http://ip:9999CodefromflaskimportFlask,......
  • virt-manager更换磁盘镜像文件安装目录
    先创建好要存储的目录,如mkdir/home/windowsimages,然后以安装windows虚拟机为例,当达到创建虚拟机的第四步,设置磁盘镜像时1、选择Selectorcreatecustomstorage->Manage) 2、创建存储池  点击Finish,就可以看到存储池中多了新建的存储  3、添加卷,设置磁盘映......
  • 如何在ipad上对pdf做笔记
    在iPad上做笔记,您可以按照以下步骤:1.选择一个文本编辑应用程序,如GoogleDocs、GoodNotes、Notability或OneNote。2.打开文本编辑器应用程序,并在其中输入要记录的文本。3.点击文本编辑器应用程序的“标记”(菜单)图标。4.从弹出的菜单中,选择“注释”选项。5.在注释选项卡上,点击“......
  • 如何对RS485设备进行地址的设置? 关于485通讯常见问题
    https://www.juyingele.com/service/2199.html 如何对RS485设备进行地址的设置?单独连接一个设备时,不管设备地址是多少,都可以使用254(广播地址)进行通讯。传输方式不同、传输距离不同、RS-232只允许一对一通信。1、传输方式不同。RS-232采取不平衡传输方式,即所谓单端......
  • 第一次git上传的完整流程
    第一次git上传的完整流程使用git简单命令上传代码push到远程仓库+简单介绍了一个.git文件结构。代码上传到gitee和github流程一样的,不过你上传到github可能网不行失败,所以我们使用gitee*前置说明你必须有git工具并且配置了环境变量。配置环境变量使用git会更方便。测......