tornado python web上传大视频文件

需求: 超过5G的视频文件,从windows磁盘,通过web服务上传到服务器的指定目录下

方式: 分块上传(前端引用webuploader框架封装好的上传方式)

原理: 前端分块每次上传20M,传入一个task_id, 后台接到文件后每次存一个文件task_id + num。待前端上传完成所有模块后,后台按照文件num顺序合成数据。

前端可执行代码:

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <script src="{{static_url('bootstrap-table/jquery-1.11.1.min.js')}}"></script>
    <script src="{{static_url('bootstrap-table/bootstrap.min.js')}}"></script>
    <script src="{{static_url('webuploader/webuploader.min.js')}}"></script>
    <script src="{{static_url('js/checkFormat.js')}}"></script>
    <link rel="stylesheet" type="text/css" href="{{static_url('webuploader/webuploader.css')}}">
    <link rel="stylesheet" type="text/css" href="{{static_url('AdminLTE-2.4.5/bower_components/bootstrap/dist/css/bootstrap.min.css')}}">
</head>

<body>
    <div>
        <div id="picker">请选择</div>   <!-- 上传按钮,必须指定id选择器的值 -->
        <div class="progress">         <!-- 进度条 -->
            <div class="progress-bar progress-bar-striped active" role="progressbar" style="width:0%;"></div>
        </div>
    </div>
    <script type="text/javascript">
    $(document).ready(function() {
        var task_id = WebUploader.Base.guid();        //产生task_id
        // console.log("-------task_id------" + task_id)
        var uploader = WebUploader.create({           //创建上传控件
            swf: "{{static_url('webuploader/Uploader.swf')}}", //swf位置,这个可能与flash有关
            server: '/cms?command=multi_upload_part',                 //接收每一个分片的服务器地址
            pick: '#picker',                          //填上传按钮的id选择器值
            auto: true,                               //选择文件后,是否自动上传
            chunked: true,                            //是否分片
            chunkSize: 20 * 1024 * 1024,              //每个分片的大小,这里为20M
            chunkRetry: 3,                            //某分片若上传失败,重试次数
            threads: 1,                               //线程数量,考虑到服务器,这里就选了1
            duplicate: true,                          //分片是否自动去重
            formData: {                               //每次上传分片,一起携带的数据
                task_id: task_id,
            },
        });

        uploader.on('startUpload', function() {       //开始上传时,调用该方法
            $('.progress-bar').css('width', '0%');
            $('.progress-bar').text('0%');
        });

        uploader.on('uploadProgress', function(file, percentage) { //一个分片上传成功后,调用该方法
            $('.progress-bar').css('width', percentage * 100 - 1 + '%');
            $('.progress-bar').text(Math.floor(percentage * 100 - 1) + '%');
        });

        uploader.on('uploadSuccess', function(file) { //整个文件的所有分片都上传成功,调用该方法
            //上传的信息(文件唯一标识符,文件名)
            // var task_id = "wu_1eddvs99e1m9q1lfsk8e1c011ro40";
            var data = {'task_id': task_id, 'filename': file.source['name'] };
            $.get('/cms?command=multi_upload_success', data);          //ajax携带data向该url发请求
            $('.progress-bar').css('width', '100%');
            $('.progress-bar').text('上传完成');
        });

        uploader.on('uploadError', function(file) {   //上传过程中发生异常,调用该方法
            $('.progress-bar').css('width', '100%');
            $('.progress-bar').text('上传失败');
        });

        uploader.on('uploadComplete', function(file) {//上传结束,无论文件最终是否上传成功,该方法都会被调用
            $('.progress-bar').removeClass('active progress-bar-striped');
        });

    });
    </script>
</body>
</html>

后端代码:

'''
# 上传
'''
def multi_upload_part(self):
   upload_file = self.request.files['file']
   task = self.get_body_argument('task_id')  # 获取文件唯一标识符
   chunk = self.get_body_argument('chunk', 0)  # 获取该分片在所有分片中的序号
   filename_temp = '%s%s' % (task, chunk)  # 构成该分片唯一标识符
   for meta in upload_file:
      filename_old = meta['filename']

      # 数据流存储
      with open('/root/upload_test/%s' % filename_temp, 'wb') as f:
         f.write(meta['body'])

      # 文件名称存储在临时文件
      with open('/root/upload_test/%s' % (str(task) + "_filename"), 'wt') as f:
         f.write(filename_old)
   return self.write({"status": 1, "res": "接收成功"})

'''
# 上传成功
'''
def multi_upload_success(self): # 按序读出分片内容,并写入新文件
   target_filename = self.get_argument('filename', '')  # 获取上传文件的文件名
   task_id = self.get_argument('task_id')  # 获取文件的唯一标识符
   temp_path = str(task_id) + "_filename"
   temp_filename_path = "/root/upload_test/" + temp_path
   if target_filename == "":
      with open(temp_filename_path, "rt") as f:
         data = f.read()
         target_filename = data
   chunk = 0  # 分片序号
   with open('/root/upload_test/%s' % target_filename, 'wb') as target_file:  # 创建新文件
      while True:
         try:
            filename = '/root/upload_test/%s%d' % (task_id, chunk)
            source_file = open(filename, 'rb')  # 按序打开每个分片
            target_file.write(source_file.read())  # 读取分片内容写入新文件
            source_file.close()
         except Exception as e:
            print("********error = ", e)
            break

         chunk += 1
         sys_pyutil.remove_file(filename)
   sys_pyutil.remove_file(temp_filename_path) # 删除该临时文件,节约空间

   return self.write({"status": 1, "res": "接收成功"})

'''
删除临时文件
'''
def remove_file(filePath):
	if os.path.exists(filePath):
		os.remove(filePath)
		return {"status": 1, "msg": "删除成功"}
	else:
		return {"status": 0, "msg": "文件不存在"}

到这里就结束了,可以愉快的开始上传了

 

参考链接:

https://blog.csdn.net/jinixin/article/details/77545140

https://github.com/jinixin/upload-demo

https://github.com/jinixin/upload-demo/blob/master/server.py

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值