• QNetworkAccessManager 实现文件上传下载-同步异步两种方式


    前言

    本文记录了在Qt应用程序中,如何使用QNetworkAccessManager实现文件的上传下载功能,qt官方推荐通过信号槽来获取文件上传或下载的进度和状态,这种方式属于异步操作,本文还介绍了一种同步上传和下载文件的实现方法。

    1 异步上传文件

    废话不多说直接上代码,如下:

    void uploadFile(const QString &localFilePath, const QString &remoteFileName)
    {
        if(localFilePath.isEmpty() || !QFile::exists(localFilePath))
        {
            return;
        }
    
    	//拼接文件上传地址
        QString strUrl = QString("http://%1:%2/upload").arg(m_hostName).arg(m_iport);
        qDebug() << strUrl;
        
        //通过设置header,实现文件上传
        QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
        QFile *uploadFile = new QFile(localFilePath);
        QHttpPart filePart;
        filePart.setHeader(QNetworkRequest::ContentDispositionHeader,
                           QVariant(QString("form-data; name=\"%1\"; filename=\"%2\"").arg("file").arg(remoteFileName)));
        uploadFile->open(QIODevice::ReadOnly);
        filePart.setBodyDevice(uploadFile);
        uploadFile->setParent(multiPart);
        multiPart->append(filePart);
    
        QUrl url(strUrl);
        //调用
        QNetworkReply *reply = m_netManager.post(QNetworkRequest(url), multiPart);
        multiPart->setParent(reply);
        reply->setProperty("localFilePath", localFilePath);
        reply->setProperty("remoteFileName", remoteFileName);
        connect(reply, SIGNAL(finished()), this, SLOT(slot_uploadFinish()));
        connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this,
                SLOT(slot_networkReplyError(QNetworkReply::NetworkError)));
        multiPart->setParent(reply); 
    }
    
    void slot_uploadFinish()
    {
        QNetworkReply *pReply = dynamic_cast<QNetworkReply *>(sender());
        if (pReply)
        {
            QString localFilePath = pReply->property("localFilePath").toString();
            QString remoteFileName = pReply->property("remoteFileName").toString();
            int code = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
            QString responseData = pReply->readAll();
            qDebug() << "description responseData :" << responseData;
            QJsonParseError error;
            QJsonDocument document = QJsonDocument::fromJson(responseData.toLocal8Bit(), &error);
            if (code != 200)
            {
                //解析失败消息
                QString message = "unknown error!";
                if (!document.isNull() && document.isObject())
                {
                    QJsonObject jsonObj = document.object();
                    message = jsonObj.value("message").toString();
                }
                emit sign_uploadFinished(false, message, remoteFileName);
            }
            else
            {
                emit sign_uploadFinished(true, localFilePath, remoteFileName);
            }
            pReply->deleteLater();
        }
        else
        {
            emit sign_uploadFinished(false, "unknown error!", "");
        }
    }
    
    • 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
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    以上代码展示了异步上传文件及上传完成后的回调处理。

    2 异步下载文件

    直接看代码

    void doDownload(const QString &downloadFilePath, const QString &remoteFileName)
    {
        QString strUrl = QString("http://%1:%2/files/%3").arg(m_hostName).arg(m_iport).arg(remoteFileName);
        qDebug() << strUrl;
        QUrl url(strUrl);
        QNetworkReply *reply = m_netManager.get(QNetworkRequest(url));
        reply->setProperty("remoteFileName", remoteFileName);
        reply->setProperty("downloadFilePath", downloadFilePath);
    
        connect(reply, SIGNAL(finished()), this, SLOT(slot_downloadFinish()));
        connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this,
                SLOT(slot_networkReplyError(QNetworkReply::NetworkError)));
    }
    
    
    void slot_downloadFinish()
    {
        QNetworkReply *pReply = dynamic_cast<QNetworkReply *>(sender());
        if (pReply)
        {
            QString localFilePath = pReply->property("downloadFilePath").toString();
            qDebug() << "downloadFinish:" << localFilePath;
            int code = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
            if (code != 200)
            {
                QString responseData = pReply->readAll();
                qDebug() << "downloadFinish responseData :" << responseData;
                QJsonParseError error;
                QJsonDocument document = QJsonDocument::fromJson(responseData.toLocal8Bit(), &error);
                //解析错误消息
                QString message = "unknown error!";
                if (!document.isNull() && document.isObject())
                {
                    QJsonObject jsonObj = document.object();
                    message = jsonObj.value("message").toString();
                }
                emit sign_downloadFinished(false, "");
            }
            else
            {
            	//保存下载文件
                QFile localFile(localFilePath);
                if (localFile.open(QIODevice::WriteOnly))
                {
                    localFile.write(pReply->readAll());
                    localFile.close();
                }
                emit sign_downloadFinished(true, localFilePath);
            }
            pReply->deleteLater();
        }
        else
        {
            emit sign_downloadFinished(false, "unknow error!");
        }
    }
    
    • 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
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    以上是异步下载文件的示例代码,下载完成后将文件内容保存在指定文件中。

    3 同步上传文件

    同步上传文件示例代码:

    bool syncUploadFile(const QString &localFilePath, const QString &remoteFileName)
    {
        if(localFilePath.isEmpty() || !QFile::exists(localFilePath))
        {
            return false;
        }
    
        QString strUrl = QString("http://%1:%2/upload").arg(m_hostName).arg(m_iport);
        qDebug() << strUrl;
    
        QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
    
        QFile *uploadFile = new QFile(localFilePath);
        QHttpPart filePart;
        filePart.setHeader(QNetworkRequest::ContentDispositionHeader,
                           QVariant(QString("form-data; name=\"%1\"; filename=\"%2\"").arg("file").arg(remoteFileName)));
        uploadFile->open(QIODevice::ReadOnly);
        filePart.setBodyDevice(uploadFile);
        uploadFile->setParent(multiPart);
        multiPart->append(filePart);
    
        QNetworkAccessManager netManager;
        QUrl url(strUrl);
        QNetworkReply *pReply = netManager.post(QNetworkRequest(url), multiPart);
        multiPart->setParent(pReply);
        
        //通过QEventLoop 阻塞主线程,直到文件上传完成。
        QEventLoop loop;
        connect(pReply, SIGNAL(finished()), &loop, SLOT(quit()));
        loop.exec();
    
        if(pReply->error() != QNetworkReply::NoError)
        {
            return false;
        }
        else
        {
            int code = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
            if (code != 200)
            {
                return false;
            }
        }
        pReply->deleteLater();
        return true;
    }
    
    • 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

    4 同步下载文件

    下面是同步下载文件的示例代码

    bool ZFTPManager::syncDownloadFile(const QString &downloadFilePath, const QString &remoteFileName)
    {
        QString strUrl = QString("http://%1:%2/files/%3").arg(m_hostName).arg(m_iport).arg(remoteFileName);
        qDebug() << strUrl;
        QUrl url(strUrl);
        QNetworkAccessManager netManager;
        QNetworkReply *pReply = netManager.get(QNetworkRequest(url));
        QEventLoop loop;
        connect(pReply, SIGNAL(finished()), &loop, SLOT(quit()));
        loop.exec();
    
        if(pReply->error() != QNetworkReply::NoError)
        {
            return false;
        }
        else
        {
            int code = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
            if (code != 200)
            {
                return false;
            }
            else
            {
                //下载成功,保存文件
                QFile localFile(downloadFilePath);
                if (localFile.open(QIODevice::WriteOnly))
                {
                    localFile.write(pReply->readAll());
                    localFile.close();
                }
            }
        }
        pReply->deleteLater();
        return true;
    }
    
    • 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

    5 总结

    本文介绍了通过使用QNetworkAccessManager实现了文件的上传和下载功能,并提供了一种同步上传下载的思路。以上就是本文的所有内容了,有不足之处欢迎指正。

  • 相关阅读:
    文件夹高效改名,批量设置文件夹仅显示编号无名称的方法“
    续:将基于Nasm汇编的打字小游戏,移植到DOSBox
    springboot瑞吉外卖
    centos7下编译安装freeswitch及常见编译问题的解决
    @Transactional事务方法中包含多个同类事务方法,这些事务方法本身设置失效两种解决方案
    Cesium Vue(四)— 物体(Entity)的添加与配置
    sci论文、ei论文和ieee论文三者之间有什么区别?
    知物由学 | Android 模拟点击研究,如何突围“黑灰产”的自动化作弊?
    爬手机app接口数据,手机不能上网问题及解决,
    No suitable driver found for jdbc:mysql://localhost:3306/BookManagement
  • 原文地址:https://blog.csdn.net/zheng19880607/article/details/132779912