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

目录

      • 前言
      • 1 异步上传文件
      • 2 异步下载文件
      • 3 同步上传文件
      • 4 同步下载文件
      • 5 总结

前言

本文记录了在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!", "");
    }
}

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

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!");
    }
}

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

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;
}

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;
}

5 总结

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

你可能感兴趣的:(C++,qt,开发语言,QNetwork,c++)