当前位置:首页 > 芯闻号 > 充电吧
[导读]简述在前面章节中我们讲述了关于Qt显示网络图片的内容,比较简单,因为图片一般都比较小,下载到本地速度比较快,所以基本不需要什么特殊处理,本节我们主要针对HTTP实现上传/下载进行详细的讲解与分享,包括

简述

在前面章节中我们讲述了关于Qt显示网络图片的内容,比较简单,因为图片一般都比较小,下载到本地速度比较快,所以基本不需要什么特殊处理,本节我们主要针对HTTP实现上传/下载进行详细的讲解与分享,包括:用户认证,实时获取下载大小、速度、剩余时间信息等。

首先看一下即将用到的公式:

文件剩余大小 = 文件总大小 - 文件已下载大小 
平均速度 = 文件已下载大小 / 文件已下载大小所用的时间 
瞬时速度 = 每秒下载的文件大小 
剩余时间 = 文件剩余大小 / 瞬时速度

下面以下载为例,来实现一个文件下载管理器。


简述效果QNetworkAccessManager使用转换总结更多参考


效果

QNetworkAccessManager

DownloadNetworkManager::DownloadNetworkManager(QObject *parent)
    : QNetworkAccessManager(parent)
{
    // 获取当前的时间戳,设置下载的临时文件名称
    QDateTime dateTime = QDateTime::currentDateTime();
    QString date = dateTime.toString("yyyy-MM-dd-hh-mm-ss-zzz");
    m_strFileName = QString("E:/%1.tmp").arg(date);

    connect(this, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *)));
}

DownloadNetworkManager::~DownloadNetworkManager()
{
    // 终止下载
    if (m_pReply != NULL)
    {
        m_pReply->abort();
        m_pReply->deleteLater();
    }
}

// 设置URL及消息头,开始请求
void DownloadNetworkManager::execute()
{
    m_url = QUrl("http://192.168.*.*/download/2.0.0.zip");

    QNetworkRequest request;
    request.setUrl(m_url);
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/zip");

    connect(this, SIGNAL(authenticationRequired(QNetworkReply *, QAuthenticator *)), this, SLOT(onAuthenticationRequest(QNetworkReply *, QAuthenticator *)));

    m_pReply = get(request);
    connect(m_pReply, SIGNAL(downloadProgress(qint64, qint64)), this, SIGNAL(downloadProgress(qint64, qint64)));
    connect(m_pReply, SIGNAL(readyRead()), this, SLOT(readyRead()));
}

void DownloadNetworkManager::replyFinished(QNetworkReply *reply)
{
    // 获取响应的信息,状态码为200表示正常
    QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);

    // 无错误返回
    if (reply->error() == QNetworkReply::NoError)
    {
        // 重命名临时文件
        QFileInfo fileInfo(m_strFileName);
        QFileInfo newFileInfo = fileInfo.absolutePath() + m_url.fileName();
        QDir dir;
        if (dir.exists(fileInfo.absolutePath()))
        {
            if (newFileInfo.exists())
                newFileInfo.dir().remove(newFileInfo.fileName());
            QFile::rename(m_strFileName, newFileInfo.absoluteFilePath());
        }
    }
    else
    {
        QString strError = reply->errorString();
        qDebug() << "Error:" << strError;
    }

    emit replyFinished(statusCode.toInt());
}

// 用户认证
void DownloadNetworkManager::onAuthenticationRequest(QNetworkReply *reply, QAuthenticator *authenticator)
{
    QByteArray password;
    password.append("123456");
    password = QByteArray::fromBase64(password);

    QString strPassword(password);

    authenticator->setUser("wang");
    authenticator->setPassword(strPassword);
}

// 本地写文件
void DownloadNetworkManager::readyRead()
{
    QFileInfo fileInfo(m_strFileName);
    QFileInfo newFileInfo = fileInfo.absolutePath() + m_url.fileName();
    QString strFileName = newFileInfo.absoluteFilePath();

    emit fileName(strFileName);

    // 写文件-形式为追加
    QFile file(m_strFileName);
    if (file.open(QIODevice::Append))
        file.write(m_pReply->readAll());
    file.close();
}

使用

调用download()接口开始下载,关联downloadProgress信号和槽,可以实时获取下载大小、速度、剩余时间等信息。

// 开始下载
void MainWindow::download()
{
    if (m_pNetworkManager == NULL)
    {
        m_pNetworkManager = new DownloadNetworkManager(this);
        connect(m_pNetworkManager, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgress(qint64, qint64)), Qt::QueuedConnection);
        connect(m_pNetworkManager, SIGNAL(replyFinished(int)), this, SLOT(replyFinished(int)), Qt::QueuedConnection);
        connect(m_pNetworkManager, SIGNAL(fileName(QString)), m_pFileInfoLabel, SLOT(setText(QString)), Qt::QueuedConnection);
    }
    m_pNetworkManager->execute();
    downloadTime.start();
}

// 计算下载大小、速度、剩余时间
void MainWindow::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
    // 总时间
    int nTime = downloadTime.elapsed();

    // 本次下载所用时间
    nTime -= m_nTime;

    // 下载速度
    double dBytesSpeed = (bytesReceived * 1000.0) / nTime;
    double dSpeed = dBytesSpeed;

    //剩余时间
    qint64 leftBytes = (bytesTotal - bytesReceived);
    double dLeftTime = (leftBytes * 1.0) / dBytesSpeed;

    m_pSpeedInfoLabel->setText(speed(dSpeed));
    m_pLeftTimeInfoLabel->setText(timeFormat(qCeil(dLeftTime)));
    m_pFileSizeInfoLabel->setText(size(bytesTotal));
    m_pDownloadInfoLabel->setText(size(bytesReceived));
    m_pProgressBar->setMaximum(bytesTotal);
    m_pProgressBar->setValue(bytesReceived);

    // 获取上一次的时间
    m_nTime = nTime;
}

// 下载完成
void MainWindow::replyFinished(int statusCode)
{
    m_nStatusCode = statusCode;
    QString strStatus = (statusCode == 200) ? QStringLiteral("下载成功") : QStringLiteral("下载失败");
    m_pStatusLabel->setText(strStatus);
}

转换

下面是一些数据的格式转换,包括:字节转KB、MB、GB,速度转KB/S、MB/S、GB/S,秒转*d *h *m *s格式。

// 字节转KB、MB、GB
QString size(qint64 bytes)
{
    QString strUnit;
    double dSize = bytes * 1.0;
    if (dSize <= 0)
    {
        dSize = 0.0;
    }
    else if (dSize < 1024)
    {
        strUnit = "Bytes";
    }
    else if (dSize < 1024 * 1024)
    {
        dSize /= 1024;
        strUnit = "KB";
    }
    else if (dSize < 1024 * 1024 * 1024)
    {
        dSize /= (1024 * 1024);
        strUnit = "MB";
    }
    else
    {
        dSize /= (1024 * 1024 * 1024);
        strUnit = "GB";
    }

    return QString("%1 %2").arg(QString::number(dSize, 'f', 2)).arg(strUnit);
}

// 速度转KB/S、MB/S、GB/S
QString speed(double speed)
{
    QString strUnit;
    if (speed <= 0)
    {
        speed = 0;
        strUnit = "Bytes/S";
    }
    else if (speed < 1024)
    {
        strUnit = "Bytes/S";
    }
    else if (speed < 1024 * 1024)
    {
        speed /= 1024;
        strUnit = "KB/S";
    }
    else if (speed < 1024 * 1024 * 1024)
    {
        speed /= (1024 * 1024);
        strUnit = "MB/S";
    }
    else
    {
        speed /= (1024 * 1024 * 1024);
        strUnit = "GB/S";
    }

    QString strSpeed = QString::number(speed, 'f', 2);
    return QString("%1 %2").arg(strSpeed).arg(strUnit);
}

// 秒转*d *h *m *s
QString timeFormat(int seconds)
{
    QString strValue;
    QString strSpacing(" ");
    if (seconds <= 0)
    {
        strValue = QString("%1s").arg(0);
    }
    else if (seconds < 60)
    {
        strValue = QString("%1s").arg(seconds);
    }
    else if (seconds < 60 * 60)
    {
        int nMinute = seconds / 60;
        int nSecond = seconds - nMinute * 60;

        strValue = QString("%1m").arg(nMinute);

        if (nSecond > 0)
            strValue += strSpacing + QString("%1s").arg(nSecond);
    }
    else if (seconds < 60 * 60 * 24)
    {
        int nHour = seconds / (60 * 60);
        int nMinute = (seconds - nHour * 60 * 60) / 60;
        int nSecond = seconds - nHour * 60 * 60 - nMinute * 60;

        strValue = QString("%1h").arg(nHour);

        if (nMinute > 0)
            strValue += strSpacing + QString("%1m").arg(nMinute);

        if (nSecond > 0)
            strValue += strSpacing + QString("%1s").arg(nSecond);
    }
    else
    {
        int nDay = seconds / (60 * 60 * 24);
        int nHour = (seconds - nDay * 60 * 60 * 24) / (60 * 60);
        int nMinute = (seconds - nDay * 60 * 60 * 24 - nHour * 60 * 60) / 60;
        int nSecond = seconds - nDay * 60 * 60 * 24 - nHour * 60 * 60 - nMinute * 60;

        strValue = QString("%1d").arg(nDay);

        if (nHour > 0)
            strValue += strSpacing + QString("%1h").arg(nHour);

        if (nMinute > 0)
            strValue += strSpacing + QString("%1m").arg(nMinute);

        if (nSecond > 0)
            strValue += strSpacing + QString("%1s").arg(nSecond);
    }

    return strValue;
}

总结

一般来说,我们下载文件到本地,需要设置一个临时文件名,这里我以时间戳为名称外加.tmp来命名,当然更严格的最好再加上随机数,这样基本就不会出现重名情况。

下载时,首先判断本地文件中是否存在与下载文件同名的文件,如果有则删除,开始下载。当下载完成时,需要对临时文件重新命名。

以上内容比较详细,介绍了如何进行用户认证,如何实时获取下载大小、速度、剩余时间等信息,后面我们会针对断点续传来进行详细讲解,敬请期待!


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

摘 要 :为解决制鞋行业中喷胶精度不高、灵活性差、生产效率低的问题,设计一种基于机器视觉的鞋模喷胶系统。该系统硬件由工业摄像头、工控机及路由器构成,软件则采用图像识别库 OpenCV 与图形界面应用程序开发框架 Qt 编...

关键字: 机器视觉 图像处理 鞋模 喷胶 OpenCV QT

嵌入式系统是指以应用为中心、以计算机技术为基础,软件硬件可裁剪、适应应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。

关键字: QT 嵌入式 C++

摘 要:仓储作为物流与供应链的核心环节,对食品安全的控制起着至关重要的作用。温湿度是影响粮食仓储过程安全与品质的重要因素。文中使用无线传感网络进行数据采集,通过Qt平台设计软件系统,并借助数据库进行数据存储与分析处理,实...

关键字: 成品粮 仓储 温湿度监测 无线传感网络 QT

在此部件上绘制行号,并将其放置在CodeEditor的viewport()的左边距区域上,QWidget类也可以帮助我们对其内容进行滚动。

关键字: QT 代码编辑器

不管是Qt新手还是开发过qt的群体来说,对Qt Designer、Qt Quick Designer、Qt Creator这几个应用程序肯定是熟悉的。

关键字: QT IDE C

在当今社会,人们的生活水平普遍提高,工作强度越来越大,营养的过剩和运动量的减少,导致心脑血管疾病的发病率是越来越高。

关键字: Linux QT GPRS 远程集群式 心脏病人实时诊断系

qt值得学习吗? 嵌入式要学的东西真的很多,我们可能会说不写界面的话就不用学qt了?我不赞同。

关键字: 嵌入式 QT UI

什么是qt?简单点说,Qt 就是一个跨平台的 C++ 图形用户界面库,可以同时支持桌面应用程序开发、嵌入式开发和移动开发,覆盖了现有的所有主流平台。

关键字: QT 程序 开发

qt值得学习吗? 嵌入式要学的东西真的很多,我们可能会说不写界面的话就不用学qt了?我不赞同,原因是……

关键字: 嵌入式 QT

HTTP协议在当今的互联网可谓是随处可见,一直默默的在背后支持着网络世界的运行,对于我们程序员来说HTTP更是熟悉不过了。平日里我们都说架构是演进的,需求推动着技术的迭代、更新和进步,对于HTTP协议来说也是如此。不知你...

关键字: http 互联网
关闭
关闭