最近在做一个文件批量上传的工具,要实现暂停继续、断点续传等功能。利用Qt自带的QtNetwork模块,完成这些需求并没有费多少周章,主要思路就是将文件分块,然后用while循环依次传输。具体实现代码比较复杂,简化了一下大致是这样子的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
int chunkUpload(UploadItem *item, const qint64 &chunkSize)
{
Q_ASSERT(item != 0);
// ...
QNetworkRequest request;
QNetworkReply* reply;
QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QBuffer* buffer = new QBuffer(multiPart);
QEventLoop loop;
QTimer timer;
// ... append fields to multiPart ...
request.setUrl(UPLOAD_URL);
reply = networkManager->post(request, multiPart);
// 保证reply销毁的时候multiPart和buffer也会随之销毁。
multiPart->setParent(reply);
// 加入一个消息循环,reply传输完成前进程会一直阻塞在这里;并设置一个定时器,如果传输超时则强制跳出消息循环
timer.setSingleShot(true);
timer.setInterval(NetworkTimeout);
connect(reply, SIGNAL(uploadProgress(qint64,qint64)), &timer, SLOT(start()));
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), &timer, SLOT(start()));
connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
timer.start();
loop.exec();
reply->deleteLater();
if (reply->isRunning())
reply->abort();
if (reply->error() != QNetworkReply::NoError)
return -1;
// ... deal with the reply ...
return 0;
}
void upload()
{
while (NOT_FINISHED) {
chunkUpload(item, CHUNK_SIZE);
}
}
程序编译运行过程很顺利,测试的时候也没发现什么问题。但后来我随手上传了一个1G大小的文件,发现每次文件上传到70%左右的时候程序就崩溃了,小文件就没这个问题。急忙打开任务管理器,这才发现上传文件的时候,程序内存占用会随着上传进度的增加而增加,上传1G文件的时候内存最多会吃到1.5G,这时候程序申请不到更多内存了,我又没做检查,当然就会崩溃掉。
限制上传文件大小这种事我是不会做的,毕竟一个上传工具占用内存比PS都高实在不科学。注意到文件上传完成之后内存会立即回到正常值,显然原因并不是我忘记释放内存而是内存释放不及时,这样看来唯一可疑的地方就是上面chunkUpload函数里面的reply->deleteLater()那一句了吧。于是我写了个方法监听reply的销毁时机,果然每一块上传完成之后reply没有销毁,直到文件全部上传完毕之后才输出一大堆“I’m destroyed…”的信息。
根据Qt文档的说明,QObject::deleteLater()并没有将对象立即销毁,而是向主消息循环发送了一个event,下一次主消息循环收到这个event之后才会销毁对象。我在这里使用deleteLater只是因为Qt文档里推荐这么做而已,其他并没多想。是这样的话一切都说得通了,因为chunkUpload函数是在一个while循环里,程序还没来得及处理这个event就立即进行下一块传输了,传输过程中生成的QNetworkReply以及它关联的QBuffer、QHttpMultiPart当然也就来不及删除了。崩溃原因找到了。你不就是来不及处理销毁对象的event嘛,手动让你处理下不就行了?于是修改upload函数代码如下:
1
2
3
4
5
6
7
void upload()
{
while (NOT_FINISHED) {
chunkUpload(item, CHUNK_SIZE);
qApp->processEvents(); // 让主程序把消息队列中的QEvent处理完
}
}
编译、运行,内存占用依然没有改变,看样子加这一行用处不大。再次查询QObject::deleteLater()的文档,发现这样一句话:
…for the object to be deleted, the control must return to the event loop from which deleteLater() was called.
这么说来,deleteLater销毁QObject的唯一时机就是程序返回主消息循环以后了呢。无奈只能放弃deleteLater。考虑到每次return前都要手动delete亦或是使用goto语句实在都不够优雅,所以利用Qt自带的QScopedPointer,修改chunkUpload函数如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
int chunkUpload(UploadItem *item, const qint64 &chunkSize)
{
Q_ASSERT(item != 0);
// ...
QNetworkRequest request;
QScopedPointer<QNetworkReply> reply;
QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QBuffer* buffer = new QBuffer(multiPart);
QEventLoop loop;
QTimer timer;
// ... append fields to multiPart ...
request.setUrl(UPLOAD_URL);
reply.reset(networkManager->post(request, multiPart));
multiPart->setParent(reply.data());
// ... event loop ...
if (reply->isRunning())
reply->abort();
if (reply->error() != QNetworkReply::NoError)
return -1;
// ... deal with the reply ...
return 0;
}
问题解决。
https://blog.yeatse.com/2015/03/18/qobject-deletelater-usage/
带进度条的文件批量上传插件uploadify
有时项目中需要一个文件批量上传功能时,个人认为uploadify是快速简便的解决方案. 先上效果图: 一. 下载uploadify 从官网下载uploadify的Flash版本(Flash版本免费,另 ...
文件批量上传-统一附件管理器-在线预览文件(有互联网和没有两种)--SNF快速开发平台3.0
实际上在SNF里使用附件管理是非常简单的事情,一句代码就可以搞定.但我也要在这里记录一下统一附件管理器能满足的需求. 通用的附件管理,不要重复开发,调用尽量简洁. 批量文件上传,并对每个文件大小限制, ...
使用WebUploader实现文件批量上传,进度条显示功能
知识点:利用WebUploader,实现文件批量上传,并且实时显示文件的上传进度 参考官方文档:http://fex.baidu.com/webuploader/ (1)引入三个资源 JS,CSS,S ...
jquery文件批量上传控件Uploadify3.2(java springMVC)
人比較懒 有用为主 不怎么排版了 先放上Uploadify的官网链接:http://www.uploadify.com/ -->里面能够看到PHP的演示样例,属性说明,以及控件下载地址.分f ...
SpringMVC+Ajax实现文件批量上传和下载功能实例代码
需求: 文件批量上传,支持断点续传. 文件批量下载,支持断点续传. 使用JS能够实现批量下载,能够提供接口从指定url中下载文件并保存在本地指定路径中. 服务器不需要打包. 支持大文件断点下载.比如下 ...
利用uploadify+asp.net 实现大文件批量上传。
前言 现在网上文件上传组件随便一搜都是一大堆,不过看大家一般都在用uploadify这个来上传文件.由于项目需要,我在来试了一下.因为第一次使用,也遇到了很多问题,特此记录! ------------ ...
uploadify文件批量上传
uploadify能够时间文件的批量上传,JS文件包下载地址,使用说明可以参考官网文档(http://www.uploadify.com/documentation/) 使用方法如下代码: $(&qu ...
stringMVC_09文件批量上传
一.思路 在文件上传的基础上引入数组可以实现批量上传,只需要更改一下前段页面和controller类即可 文件上传: https://www.cnblogs.com/aihuadung/p/10167 ...
ASP.NET MVC WebAPI实现文件批量上传
工作中学习,学习中记录~~~~~~ 最下面附上demo 任务需求:需要做一个apI接口让C#的程序调用实现批量文件的上传. 难度: 没有做过通过API上传文件的...之前做过网站前后台上传. 首先当然 ...
随机推荐
c#链接数据库
using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Linq; usin ...
HOJ 1640 Mobile Phone
题意:有一个n*n的矩阵,op==1时,在(x,y)增加值z,op==2时,求以(x1,y1)和(x2,y2)构成的矩阵的和. 思路:二维线段树. 代码: #include
WebService优点和缺点小结(转)
一.什么是WebService? 实际上,WebService的主要目标是跨平台的可互操作性.为了达到这一目标,WebService完全基于XML(可扩展标记语言).XSD (XMLSchema) ...
hdu4638 group 树状数组
连接:http://acm.hdu.edu.cn/showproblem.php?pid=4638 题意:就给给你n个数(大小在1-n里),然后给你连续的可以构成一个块,再给你N个询问,每个询问一个l ...
oracle行转列
wm_concat()函数 --创建表 create table test(id number,name varchar2(20)); --插入数据 insert into test values(1 ...
Ribbon Control
https://documentation.devexpress.com/#WindowsForms/CustomDocument2492 The Ribbon Control replaces tr ...
初时Python博大精深
Python是解释型语言 编译型vs解释型 编译型优点:编译器一般会有预编译的过程对代码进行优化.因为编译只做一次,运行时不需要编译,所以编译型语言的程序执行效率高.可以脱离语言环境独立运行.缺点:编 ...
天马行空-Ops平台建设概述
1 概述 什么是Ops平台,Ops平台的目标是什么,建设的考虑点有哪些?本章节以实际生活中医院的例子来进行各形象的阐述. 医院包含各种诊断治疗设备,病历库,医生.一个孕妇需要到医院 ...
JavaScript中对象属性的加入和删除
...