想借着这篇文章简要谈谈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框架。 后端要做的是接收这一大堆分片,然后将它们重新合并成一个文件,那么有如下三个问题:
WebUploader已经为我们解决了,详见下面代码。
方案三:为每个分片创建一个新的临时文件来保存其内容;待全部分片上传完毕后,再按顺序读取所有临时文件的内容,将数据写入新文件中。
前两个方案看似不错,但其实有些问题。方案一因等待所有分片的时间过长容易造成内存溢出;由于分片不一定是按序上传,所以方案二也不行;故只能选择方案三了。
请选择
@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(): # 所有分片均上传完后被调用
target_filename = request.args.get('filename') # 获取上传文件的文件名
task = request.args.get('task_id') # 获取文件的唯一标识符
chunk = 0 # 分片序号
with open('./upload/%s' % target_filename, 'wb') as target_file: # 创建新文件
while True:
try:
filename = './upload/%s%d' % (task, chunk)
source_file = open(filename, 'rb') # 按序打开每个分片
target_file.write(source_file.read()) # 读取分片内容写入新文件
source_file.close()
except IOError:
break
chunk += 1
os.remove(filename) # 删除该分片,节约空间
return rt('./index.html')
如果有想要源码的朋友,可以移步这里。对该项目还会不断改进,如果你感兴趣,不妨star一下,谢谢。