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

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

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实现了文件的上传和下载功能,并提供了一种同步上传下载的思路。以上就是本文的所有内容了,有不足之处欢迎指正。

QNetworkAccessManagerQt框架中的网络访问管理器,用于处理HTTP、HTTPS等协议的网络请求。对于FTP大文件的高速下载,你可以利用QNetworkAccessManager来发送FTP下载命令,并通过`qNetworkReply`对象来跟踪和管理下载过程。以下是基本步骤: 1. **创建QNetworkRequest**:首先,你需要构建一个指向FTP服务器上文件的QNetworkRequest,指定FTP协议(通常是"ftp://"加上URL)。 ```cpp QUrl url("ftp://username:password@ftp.example.com/path/to/large/file"); QNetworkRequest request(url); ``` 2. **设置连接管理器**:使用QNetworkAccessManager实例来发起请求。 ```cpp QNetworkAccessManager *manager = new QNetworkAccessManager(this); connect(manager, &QNetworkAccessManager::finished, this, &YourClass::handleFinished); ``` 3. **开始下载**:调用`get()`方法开始下载,传递请求对象。 ```cpp QNetworkReply *reply = manager->get(request); ``` 4. **处理下载进度**:`handleFinished`槽函数会被调用,你可以检查下载状态并更新进度。同时,`progress`信号可以让你获取下载的实时进度。 ```cpp void YourClass::handleFinished(QNetworkReply *reply) { if (reply->error() == QNetworkReply::NoError) { // 下载成功,处理文件数据 } else { // 处理错误 } qint64 bytesReceived = reply->bytesAvailable(); qint64 totalBytes = reply->totalSize(); // 更新进度条或显示下载速度 } ``` 5. **断点续传**:为了实现高速下载,FTP客户端通常支持断点续传,如果要在下载过程中恢复,需要保存上次中断的位置信息,然后在下次请求时从该位置开始。 请注意,这只是一个基础示例,实际应用可能还需要处理更多的细节,比如错误处理、超时控制和用户交互提示。另外,在高并发或多线程环境下,你可能需要对下载操作进行适当的管理和同步
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凝望星辰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值