转载请注明出处:http://blog.csdn.net/jinixin/article/details/77545140

引言想借着这篇文章简要谈谈WebUploader大文件上传与Python结合的实现。

WebUploader是百度团队对大文件上传的前端实现,而后端需要根据不同的语言自己实现。这里我采用Python语言的Flask框架搭建后端,配合使用Bootstrap前端框架渲染上传进度条,效果图在文章底部。

WebUploader官网:点这里;WebUploader API:点这里;

实施http协议并不是非常适合上传大文件,所以要考虑分片,即把大文件分割后再上传,而WebUploader所做的事,正是将一个大文件分片,一部分一部分的上传到服务器。在上传每个分片的http请求中,需要同时携带:

1)该文件的唯一标识:task_id;

2)该文件的分片总数:chunks;

3)该分片在该文件所有分片中的位置:chunk;

其中后两个WebUploader已经替我们自动上传了,而第一个task_id仅需要我们调用对应函数即可产生,然后再将其写入form-data。

WebUploader是一个前端框架,所以接收文件的部分需要我们自己实现,而我选用了Python和其的Flask框架。
后端要做的是接收这一大堆分片,然后将它们重新合并成一个文件,那么有如下三个问题:

1)如何判定某个分片上传后,是不是整个文件也上传结束了?

WebUploader已经为我们解决了,详见下面代码。

$(document).ready(function() {

var task_id = WebUploader.Base.guid(); //产生task_id,唯一标识该文件

var uploader = WebUploader.create({

server: '/upload/accept', //服务器接收并处理分片的url地址

formData: {

task_id: task_id, //上传分片的http请求携带的数据

},

});

uploader.on('uploadSuccess', function(file) { //当该文件所有分片均上传成功时调用该函数

//上传的信息(文件唯一标识符,文件后缀名)

var data = { 'task_id': task_id, 'ext': file.source['ext'], 'type': file.source['type'] };

$.get('/upload/complete', data); //ajax携带data向该url发请求

});

});

2)如何处理接收分片和将分片内容写入文件的关系?

方案一:开一个字符串,一边接收分片,一边将分片里的内容读取出来后添加到字符串末尾;全部分片接收完毕后,再将字符串写入新文件中。

方案二:创建一个文件,一边接收分片,一边将分片里的内容读取出来写入文件末尾。

方案三:为每个分片创建一个新的临时文件来保存其内容;待全部分片上传完毕后,再按顺序读取所有临时文件的内容,将数据写入新文件中。

前两个方案看似不错,但其实有些问题。方案一因等待所有分片的时间过长容易造成内存溢出;由于分片不一定是按序上传,所以方案二也不行;故只能选择方案三了。

3)后端如何区分不同用户的文件?如何区分同个文件不同分片的先后顺序?

通过http请求携带的task_id可以区分不同的文件。同个文件分片的先后顺序,可以通过http请求携带的chunk来区分。因此,task_id+chunk的组合可以在众多不同用户不同文件的分片中唯一标记某个分片,即某个文件的某个分片名称是task_id+chunk。

关键代码

前端代码

请选择

$(document).ready(function() {

var task_id = WebUploader.Base.guid(); //产生task_id

var uploader = WebUploader.create({ //创建上传控件

swf: './static/webuploader/Uploader.swf', //swf位置,这个可能与flash有关

server: '/upload/accept', //接收每一个分片的服务器地址

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 data = {'task_id': task_id, 'ext': file.source['ext'], 'type': file.source['type']};

$.get('/upload/complete', 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');

});

});

后端代码@app.route('/', methods=['GET', 'POST'])

def index(): # 一个分片上传后被调用

if request.method == 'POST':

upload_file = request.files['file']

task = request.form.get('task_id') # 获取文件唯一标识符

chunk = request.form.get('chunk', 0) # 获取该分片在所有分片中的序号

filename = '%s%s' % (task, chunk) # 构成该分片唯一标识符

upload_file.save('./upload/%s' % filename) # 保存分片到本地

return rt('./index.html')

@app.route('/success', methods=['GET'])

def upload_success(): # 所有分片均上传完后被调用

task = request.args.get('task_id')

ext = request.args.get('ext', '')

upload_type = request.args.get('type')

if len(ext) == 0 and upload_type:

ext = upload_type.split('/')[1]

ext = '' if len(ext) == 0 else '.%s' % ext # 构建文件后缀名

chunk = 0

with open('./upload/%s%s' % (task, ext), 'w') as target_file: # 创建新文件

while True:

try:

filename = './upload/%s%d' % (task, chunk)

source_file = open(filename, 'r') # 按序打开每个分片

target_file.write(source_file.read()) # 读取分片内容写入新文件

source_file.close()

except IOError:

break

chunk += 1

os.remove(filename) # 删除该分片,节约空间

return rt('./index.html')

结果

效果图

测试三台计算机,一台做服务器,分别在另两台上同时各上传一本电影,大小为2.6G与3.8G;上传完毕后,两本电影均可在服务器上正常播放。

未来后续会对Django和Tornado框架做补充,如果有想要源码的朋友,可以移步这里。对该项目还会不断改进,如果你感兴趣,不妨star一下,谢谢。

python 大文件分片上传_Python实现大文件分片上传相关推荐

  1. python django下载 功能如何实现_Python中django文件传输下载功能的实现

    Python中django文件传输下载功能的实现,基于Django建立的网站,如果提供文件下载功能,最简单的方式莫过于将静态文件交给Nginx等处理,但有些时候,由于网站本身逻辑,需要通过Django ...

  2. python读取字符串指定位置字符_python读取txt文件中特定位置字符的方法

    python读取txt文件中特定位置字符的方法 如下所示: # -*- coding:utf-8 -*- import sys reload(sys) sys.setdefaultencoding(' ...

  3. python创建文本、判断该文件共有多少行_python如何判断文件有多少行

    如何统计读取的一个txt文本的行数呢? 云海天教程网,大量的免费python教程,欢迎在线学习! 最简单的办法是把文件读入一个大的列表中,然后统计列表的长度.如果文件的路径是以参数的形式filepat ...

  4. python 文件操作不被打断_python学习六文件操作和异常处理

    1.文件的定义和类型 什么是文件呢? 文件是数据的抽象和集合 文件是存储在辅助存储器上的数据序列 文件是存储的一种 文件有哪些类型呢? 本质上所有文件以二进制储存,不过又可以分为文本文件和二进制文件 ...

  5. python docx 合并文档 图片_Python检查Word文件中包含特定关键字的所有页码

    推荐教材:<Python程序设计基础与应用>(ISBN:9787111606178),董付国,机械工业出版社图书详情:配套资源:用书教师可以联系董老师获取教学大纲.课件.源码.教案.考试系 ...

  6. python读取json文件制作中国人口地图_Python对JSON文件世界人口数据进行可视化

    制作世界人口地图,用json模块来处理,将人口数据进行可视化!!! 下载JSON格式的人口数据,下面附上完整的,在网站中https://datahub.io/下载的数据集的详细过程!!! 1.下载世界 ...

  7. python复制文件的方法是_Python中复制文件的9种方法

    Python 中有许多"开盖即食"的模块(比如 os,subprocess 和 shutil)以支持文件 I/O 操作.在这篇文章中,你将会看到一些用 Python 实现文件复制的 ...

  8. python读取txt文件的行数_python读取txt文件符合条件的行数-女性时尚流行美容健康娱乐mv-ida网...

    女性时尚流行美容健康娱乐mv-ida网 mvida时尚娱乐网 首页 美容 护肤 化妆技巧 发型 服饰 健康 情感 美体 美食 娱乐 明星八卦 首页 > 高级搜索 python 关系网图 pyth ...

  9. python中表头格式错误导入_python读csv文件时指定行为表头或无表头的方法

    pd.read_csv()方法中header参数,默认为0,标签为0(即第1行)的行为表头.若设置为-1,则无表头.示例如下: (1)不设置header参数(默认)时: df1 = pd.read_c ...

最新文章

  1. 设计模式:单例模式之懒汉式
  2. 9月19日下午JavaScript数组冒泡排列和二分法
  3. Python常用模块之hashlib模块
  4. R:matlab交互,数据调用
  5. oracle 数据库 锁
  6. Leetcode周赛复盘——第 276 场力扣周赛
  7. mysql like 多个条件_千万级MySQL数据库这样建索引可以让你的数据库飞起来.........
  8. bzoj1211: prufer序列 | [HNOI2004]树的计数
  9. VS Code 神器插件:代码一键运行,支持超过 40 种语言!
  10. Restore IP Address-深度优先遍历DFS
  11. NoSQL 已死:我们不需要他了
  12. 点云投影_激光点云变换到图像平面并保存成int16灰度图一帧激光点云+一张RGB图像得到彩色点云
  13. Atitit 招人之道 招不到人怎么办 attilax著 1. 适当降低要求 水至清则无鱼 太严格了就没有人了 2 1.1. 学历可以提升 可以开个企业内部学院快速提升学历 2 1.2. ,能力可以
  14. javaweb不同用户登录不同页面的页面_ssh+mysql实现的Java web论坛系统源码附带视频指导运行教程...
  15. 用AJAX方式上传图片文件
  16. 熊出没机器人光头强_《熊出没》五大兵器,天才威与光头强的战斗机器人谁更厉害?...
  17. validate.js 插件表单校验
  18. 华大单片机HC32L130使用内部RCH时钟源倍频24M外设PCLK到48M
  19. iPhone手机数据找回指南2:iPhone手机使用技巧
  20. VS2017 创建安装项目模板

热门文章

  1. Win10系统,如何使用系统自带截图工具 “PrintScreen键“
  2. 解决Linux(ubuntu),windows双系统重装后恢复开机选单
  3. Prometheus + Grafana 实现监控功能总结
  4. 鹅肉是凉性还是热性 鹅肉怎么做好吃
  5. 【集合论】偏序关系 ( 偏序关系定义 | 偏序集定义 | 大于等于关系 | 小于等于关系 | 整除关系 | 包含关系 | 加细关系 )
  6. Java 汽车租赁管理系统
  7. 打开一次outlook msg格式邮件后就不能再打开
  8. 语音识别学习记录 [kaldi中的openfst]
  9. 测试代理ip是否有效
  10. 威海海燕计算机学校,与中成学校一起成长 ——高海燕