这里我们涉及到了一种算法——分支算法
最近着手的广告平台项目中,因为需要客户提供自证视频,证明是本人公司的真实性。
现如今,视频的分辨率越发的高,往往就伴随着视频内存的巨大,一个几分钟的视频需要几个g的内存,用普通的上传方法肯定不行,文件大速度慢,影响客户的使用体验,为了解决这个问题,我采用了分片上传的方法,将一个大文件,分成n个小文件进行上传,加快传输效率!
这里我们涉及到了一种算法——分支算法
分片上传的概念就是分治算法,分而治之,将一个大问题,转变为多个小问题,进行解决!!
前端分片
首先分片我们是在前端做的,分片传输给后端,这里我用的是vue3,ui框架为ant-desgin,用到的控件为a-upload,用户点击上传选择要上传的文件。
这时我们可以得到文件的名字,以及大小,然后定义你要分片的大小,这里可以写一个判断,跟你你要上传文件的大小,定义你分片的大小,如果文件太小的话,就没有必要进行分片,占用资源。这时候我们就可以拿到总片数,因为会有余数,所以我使用的是Math.ceil向上取整的方法,拿到总片数。这时候我们就可以拿到每次切片的起始位置和结束位置了,然后通过slice对文件进行切片,发给后端进行处理!
//上传方法
handleChange:function(file){
//获取文件大小 1024字节 1kb
console.log(file.file)
var size = file.file.size
this.size = size
// this.filename = file.file.name
//定义分片大小
var shardSize = 1024 * 100
//总片数
//向上取整
this.shardCount = Math.ceil(size / shardSize)
//切片操作
for (var i=0;i<this.shardCount; ++i){
//开始位置
var start = i * shardSize
//结束位置
var end = Math.min(size,start+shardSize)
//切片
var shardfile = file.file.slice(start,end)
this.pushshard(shardfile,file.file.name,i)
}
},
至此前端分片逻辑就完成了!
后端异步写入
后端我使用的是python中的tronado框架异步写入,为了避免同步写入引起阻塞,安装aiofiles库配合着tornado的异步机制,可以提高写入的效率
这里后端获取到文件实体,文件名,标志位,先将文件实体异步写入指定路径中,然后进行读取,按顺序合并,文件操作我就不做过多的讲述了,都是一些固定语法,也没什么逻辑,下面代码展示,请自行观看
# 分片上传
class SliceUploadHandler(BaseHandler):
#合并分片
async def put(self):
filename = self.get_argument("filename",None)
count = 0
size = self.get_argument("size",None)
try:
filesize = os.path.getsize("./static/upload/{}".format(filename))
except Exception as e:
print(str(e))
filesize = 0
if int(size) != filesize:
#异步打开文件句柄
async with aiofiles.open("./static/upload/{}".format(filename),"ab") as file:
while True:
try:
#读取分片
shard_file = open("./static/upload/{}_{}".format(filename,count),"rb")
#异步写入
await file.write(shard_file.read())
#手动关闭句柄
shard_file.close()
except Exception as e:
print(str(e))
break
count = count + 1
self.finish({"errcode":0,"msg":"合并完毕"})
# 分片文件接收
async def post(self):
#接收分片实体
file = self.request.files["file"][0]
#获取下标
count = self.get_argument("count",None)
#获取文件名
filename = self.get_argument("filename",None)
#获取文件内容
content = file["body"]
#异步写入
async with aiofiles.open("./static/upload/{}_{}".format(filename,count),"wb") as file:
#异步
await file.write(content)
self.finish({"errcode":0,"msg":"分片上传成功"})
至此前后端就调试完成了,除此之外,在真实的超大文件传输场景中,由于网络或者其他因素,很可能导致分片任务中断,此时就需要通过降级快速响应,返回托底数据,避免用户的长时间等待,这里我们使用基于Tornado的Apscheduler库来调度分片任务。