Network Download Manager Example▲
Sélectionnez
/**
**************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
***************************************************************************
*/
#include
"downloadmanager.h"
#include <QTextStream>
#include <cstdio>
using
namespace
std;
DownloadManager::
DownloadManager(QObject *
parent)
:
QObject(parent)
{
}
void
DownloadManager::
append(const
QStringList &
amp;urls)
{
for
(const
QString &
amp;urlAsString : urls)
append(QUrl::
fromEncoded(urlAsString.toLocal8Bit()));
if
(downloadQueue.isEmpty())
QTimer::
singleShot(0
, this
, SIGNAL(finished()));
}
void
DownloadManager::
append(const
QUrl &
amp;url)
{
if
(downloadQueue.isEmpty())
QTimer::
singleShot(0
, this
, SLOT(startNextDownload()));
downloadQueue.enqueue(url);
++
totalCount;
}
QString DownloadManager::
saveFileName(const
QUrl &
amp;url)
{
QString path =
url.path();
QString basename =
QFileInfo(path).fileName();
if
(basename.isEmpty())
basename =
"download"
;
if
(QFile::
exists(basename)) {
// already exists, don't overwrite
int
i =
0
;
basename +=
'.'
;
while
(QFile::
exists(basename +
QString::
number(i)))
++
i;
basename +=
QString::
number(i);
}
return
basename;
}
void
DownloadManager::
startNextDownload()
{
if
(downloadQueue.isEmpty()) {
printf("%d/%d files downloaded successfully
\n
"
, downloadedCount, totalCount);
emit finished();
return
;
}
QUrl url =
downloadQueue.dequeue();
QString filename =
saveFileName(url);
output.setFileName(filename);
if
(!
output.open(QIODevice::
WriteOnly)) {
fprintf(stderr, "Problem opening save file '%s' for download '%s': %s
\n
"
,
qPrintable(filename), url.toEncoded().constData(),
qPrintable(output.errorString()));
startNextDownload();
return
; // skip this download
}
QNetworkRequest request(url);
currentDownload =
manager.get(request);
connect(currentDownload, SIGNAL(downloadProgress(qint64,qint64)),
SLOT(downloadProgress(qint64,qint64)));
connect(currentDownload, SIGNAL(finished()),
SLOT(downloadFinished()));
connect(currentDownload, SIGNAL(readyRead()),
SLOT(downloadReadyRead()));
// prepare the output
printf("Downloading %s...
\n
"
, url.toEncoded().constData());
downloadTime.start();
}
void
DownloadManager::
downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
progressBar.setStatus(bytesReceived, bytesTotal);
// calculate the download speed
double
speed =
bytesReceived *
1000.0
/
downloadTime.elapsed();
QString unit;
if
(speed &
lt; 1024
) {
unit =
"bytes/sec"
;
}
else
if
(speed &
lt; 1024
*
1024
) {
speed /=
1024
;
unit =
"kB/s"
;
}
else
{
speed /=
1024
*
1024
;
unit =
"MB/s"
;
}
progressBar.setMessage(QString::
fromLatin1("%1 %2"
)
.arg(speed, 3
, 'f'
, 1
).arg(unit));
progressBar.update();
}
void
DownloadManager::
downloadFinished()
{
progressBar.clear();
output.close();
if
(currentDownload-&
gt;error()) {
// download failed
fprintf(stderr, "Failed: %s
\n
"
, qPrintable(currentDownload-&
gt;errorString()));
output.remove();
}
else
{
// let's check if it was actually a redirect
if
(isHttpRedirect()) {
reportRedirect();
output.remove();
}
else
{
printf("Succeeded.
\n
"
);
++
downloadedCount;
}
}
currentDownload-&
gt;deleteLater();
startNextDownload();
}
void
DownloadManager::
downloadReadyRead()
{
output.write(currentDownload-&
gt;readAll());
}
bool
DownloadManager::
isHttpRedirect() const
{
int
statusCode =
currentDownload-&
gt;attribute(QNetworkRequest::
HttpStatusCodeAttribute).toInt();
return
statusCode ==
301
||
statusCode ==
302
||
statusCode ==
303
||
statusCode ==
305
||
statusCode ==
307
||
statusCode ==
308
;
}
void
DownloadManager::
reportRedirect()
{
int
statusCode =
currentDownload-&
gt;attribute(QNetworkRequest::
HttpStatusCodeAttribute).toInt();
QUrl requestUrl =
currentDownload-&
gt;request().url();
QTextStream(stderr) &
lt;&
lt; "Request: "
&
lt;&
lt; requestUrl.toDisplayString()
&
lt;&
lt; " was redirected with code: "
&
lt;&
lt; statusCode
&
lt;&
lt; '
\n
'
;
QVariant target =
currentDownload-&
gt;attribute(QNetworkRequest::
RedirectionTargetAttribute);
if
(!
target.isValid())
return
;
QUrl redirectUrl =
target.toUrl();
if
(redirectUrl.isRelative())
redirectUrl =
requestUrl.resolved(redirectUrl);
QTextStream(stderr) &
lt;&
lt; "Redirected to: "
&
lt;&
lt; redirectUrl.toDisplayString()
&
lt;&
lt; '
\n
'
;
}