Qt使⽤QNetworkAsssManager下载⽂件功能⽬录:
1. QNetworkAccessManager接⼝介绍
2. 下载进度条展⽰,⽀持暂停,停⽌功能
3. 显⽰下载/剩余⼤⼩,剩余时间,下载速度
4. 多线程下载,不阻塞界⾯线程
5. ⽂件断点续传下载
6. 下载请求超时的处理
7. 功能实现Demo地址
1.QNetworkAccessManager接⼝介绍
可以⼀⽬了然的看到⼏个熟悉词汇的api:post、get、put、head,当然还有⼏个cookie相关的⽅法。
可以发现使⽤manager还需要⼏个类:QNetworkRequest 专门⽤于请求的,QNetworkReply 接收请求的响应.
⽐如1.只想从⽹页服务器上请求数据,使⽤get⽅法。
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
QNetworkRequest request;
request.tUrl(QUrl("qt-project"));
reply = manager->get(request);
connect(reply, &QNetworkReply::finished, this, &MainWindow::finished);
//在finished函数中
QByteArray bytes = reply->readAll();//读取⽹页数据
2.附带数据向服务器请求返回数据,使⽤post,当post附带json数据时:
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QNetworkRequest request;
//构造json数据
小儿垂钓的作者是谁
QJsonObject jsonObject;
jsonObject.inrt("dcode", "code");
jsonObject.inrt("ver", "version");
//json转QByteArray
QString strJson = QString(QJsonDocument(jsonObject).toJson(QJsonDocument::Compact));
QByteArray byte_json = Local8Bit();
request.tUrl(QUrl("qt-project"));//要请求的地址
//如果请求json数据,请求header要使⽤此设置
罗大佑追梦人request.tHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));
if (m_Reply != Q_NULLPTR) {
祖鲁战争m_Reply->deleteLater();
}
m_Reply = manager->post(request, byte_json);
QEventLoop loop;//⾮阻塞⽅式,采⽤事件循环
QTimer timer;
connect(m_Reply, SIGNAL(finished()), &loop, SLOT(quit()));大胸美女桌面壁纸
QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
timer.start(5000);//设置超时5s
<(QEventLoop::ExcludeUrInputEvents);
if (m_Reply->error() == QNetworkReply::NoError){
QByteArray strJsonText = m_Reply->readAll();//请求返回数据
}
1.1. QNetworkRequest
主要就是这⼏个写⽅法,分别对⼀个请求的不同类进⾏配置。
客户端发送⼀个HTTP请求到服务器的请求消息包括以下格式:请求⾏(request line)、请求头部(header)、空⾏和请 求数据四个部分组成,下图给出了请求报⽂的⼀般格式。请求⾏组成:请求⽅法+空格+url+空格+协议版本+回车符+换⾏符。 详情见HTTP 消息结构
对于header,qt提供了⼀个枚举类型KnownHeaders分别表⽰不同项:
Constant Value Description
QNetworkRequest::ContentDispositionHeader6Corresponds to the HTTP Content-Disposition header and contains a string containing the disposition type (for instance, attachment) and a parameter (for instance, filename).
QNetworkRequest::ContentTypeHeader0Corresponds to the HTTP Content-Type header and contains a string containing the media (MIME) type and any auxiliary data (for instance, chart).
QNetworkRequest::ContentLengthHeader1Corresponds to the HTTP Content-Length header and contains the length in bytes of the data transmitted.
QNetworkRequest::LocationHeader2Corresponds to the HTTP Location header and contains a URL reprenting the actual location of the data, including the destination URL in ca of redirections.
QNetworkRequest::LastModifiedHeader3Corresponds to the HTTP Last-Modified header and contains a reprenting the last modification date of the contents.
QNetworkRequest::CookieHeader4Corresponds to the HTTP Cookie header and contains a <> reprenting the cookies to be nt back to the rver.
QNetworkRequest::SetCookieHeader5Corresponds to the HTTP Set-Cookie header and contains a <> reprenting the cookies nt by the rver to be stored locally.
拉雷手QNetworkRequest::UrAgentHeader7The Ur-Agent header nt by HTTP clients.
猪气喘病
QNetworkRequest::ServerHeader8The Server header received by HTTP clients.
1.2. QNetworkReply
此类继承⾃QIODevice,可使⽤QIODevice的所有接⼝,包括readall读取接收的所有信息。
同时此类提供了finished信号,在响应完斥候发出此信号,可关联⾃定义槽函数函数,做响应处理。
提供了attribute属性函数,可以判断响应的类型,⽐如RedirectionTargetAttribute是⽬标url告知进⾏重定向
QNetworkReply不会⾃动释放空间,⼀定要主动处理内存释放,可以调⽤QObject::deleteLater令其⾃动释放空间
connect(m_reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(onDownloadProgress(qint64, qint64)));
connect(m_reply, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
connect(m_reply, SIGNAL(finished()), this, SLOT(onFinished()));
connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError)));
如果请求下载功能:
onDownloadProgress(qint64, qint64);显⽰的就是下载的进度,参数1和2分别代表本次下载字节数和⽂件总字节⼤⼩。onReadyRead();下载过程中开始从服务器读取数据,⽤于读取数据写⼊本地⽂件中,采⽤数据追加的⽅式⽅便断点的续传:
void xx::onReadyRead()
{
if (m_reply == NULL) return;
QFile file(m_fileName);//本地⽂件名
if (file.open(QIODevice::WriteOnly | QIODevice::Append))
{
file.write(m_reply->readAll());
}
file.clo();
渐近线怎么求
}
onFinished():下载完成事件。
onError():下载错误事件
2.下载进度条展⽰,⽀持暂停,停⽌功能
QNetworkAccessManager使⽤get⽅法发送请求,使⽤QNetworkReply接受返回。QNetworkReply使⽤下载进程信号来反馈每次下载数据的⼤⼩和⽂件的总⼤⼩。
2.1 readyRead()
这是QNetworkReply的⽗类QIODevice提供的下载过程中的信号,可以在此信号中写⼊下载⽂件⼤⼩。
2.2 downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
bytesReceived代表每次下载⽂件字节⼤⼩,bytesTotal代表下载⽂件字节总⼤⼩。
//更新进度条;
QString sValue = QString("%1").arg(bytesReceived * 100 / (bytesTotal));//百分⽐,所以乘以100
ui.progressBar->Int());
2.3 暂停和停⽌功能要点:需要解绑QNetworkReply的信号和槽,并调⽤QNetworkReply的abort⽅法和DeleteLater()⽅法。
disconnect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onDownloadProgress(qint64, qint64)));
disconnect(m_reply, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
disconnect(m_reply, SIGNAL(finished()), this, SLOT(onFinished()));
disconnect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError)));
m_reply->abort();
m_reply->deleteLater();
m_reply = NULL;
3.显⽰下载/剩余⼤⼩,剩余时间,下载速度
计算剩余⼤⼩,剩余时间和下载速度,需要根据下载过程中每次下载字节数和总下载字节数计算,所以还是在downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
响应的槽函数中来计算。
// 下载⼤⼩MB/总⼤⼩MB
QString strDownCurrent = QStringLiteral("下载⼤⼩:%1/%2").arg(transformUnit(m_currentDownload)).arg(transformUnit(bytesTotal)); ui.lb_size->tText(strDownCurrent);
//剩余时间
qint64 ispeed = m_intervalDownload * 1000 / (timeNow - m_timeInterval);
qint64 timeRemain = (bytesTotal - bytesReceived) / ispeed;
QString strRemaind = QStringLiteral("剩余时间:%1").arg(transformTime(timeRemain));
ui.lb_remaind->tText(strRemaind);
苏武简介资料//下载速度
QString strSpeed = QStringLiteral("下载速度:%1").arg(transformUnit(ispeed, true));
ui.lb_rate->tText(strSpeed);
4.多线程下载,不阻塞界⾯线程
此处有两种⽅法,⼀种是通过MoveToThread⽅法,通过⼀个继承与QObject的功能类实现。
⼆是继承QThread,通过QThread来实现多线程,我使⽤的是第⼆种,提供过⼀个继承与QThread的中间类。
当点击下载按钮时,启动下载线程:
m_strTargetAddress = "d:/Qt_Download.zip";//⾃定义⽬标下载地址
QString strUrl = ui.lineEdit->text();//服务器下载地址
if (m_pDownloadThread != NULL )
{
m_pDownloadThread->start();
}
5.⽂件断点续传下载
5.1关于断点续传,QNetworkRequest提供了⽅法SetRawHeader和"Range"字段来设置请求的字节⼤⼩和宽度。
在HTTP协议请求中,如果想从⽂件的某⼀位置接受数据,就要加上Range头部,Range头部的格式有如下⼏种情况:
表⽰头500个字节:bytes=0-499
表⽰第⼆个500字节:bytes=500-999
表⽰最后500个字节:bytes=-500
表⽰500字节以后的范围:bytes=500-
第⼀个和最后⼀个字节:bytes=0-0,-1
同时指定⼏个范围:bytes=500-600,601-999
在发出带Range的请求后,服务器会在Content-Range头部返回当前接受的范围和⽂件总⼤⼩,如:
Content-Range: 0-499/22400
这⾥0-499是指当前发送的数据的范围,⽽22400则是⽂件的总⼤⼩。
5.2要实现断点续传,只有客户端是不⾏的,服务器上的⽂件也必须⽀持断点续传,也就是说,在进⾏断点下载续传时,⾸先要判断要下载⽂件是否⽀持断点下载。
windows下如何判断⽀持要下载⽂件⽀持断点下载:
5.2.1 cmd下使⽤curl 命令加 -i 参数 和要请求的字节⼤⼩
HTTP/1.1 206 Partial Content
Date: Wed, 01 Aug 2018 03:12:14 GMT
Content-Type: application/zip
Content-Length: 10
Last-Modified: Wed, 07 Dec 2016 10:13:32 GMT
Connection: keep-alive
ETag: "5847e0cc-78ac98"
Content-Range: bytes 0-9/7908504
处Content-Range: bytes 0-9/7908504 返回的字节数7908504就是⽂件的总字节⼤⼩。
HTTP/1.1 206 Partial Content 代表状态值206 代表⽀持断点下载
所以此处返回带有Content-Range和HTTP/1.1 206 Partial Content字节,代表此链接是⽀持断点下载的。
5.2.2 Qt代码中通过QNetworkRequest发送请求"Range",通过返回值QNetworkReply的rawHeader("Content-Range")是否存在返回值来查看。