分而治之,大型文件分片上传

这里我们涉及到了一种算法——分支算法

最近着手的广告平台项目中,因为需要客户提供自证视频,证明是本人公司的真实性。

现如今,视频的分辨率越发的高,往往就伴随着视频内存的巨大,一个几分钟的视频需要几个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库来调度分片任务。

猜你喜欢

转载自blog.csdn.net/qwertyu111j/article/details/126038796