#ifndef FILETRANSFER_H #define FILETRANSFER_H #include #include #include #include #include #include #include #include #include class FileTransfer : public QObject { Q_OBJECT Q_PROPERTY(double downloadProgress READ downloadProgress NOTIFY downloadProgressChanged) Q_PROPERTY(double uploadProgress READ uploadProgress NOTIFY uploadProgressChanged) public: static FileTransfer* instance() { static FileTransfer _instance; return &_instance; } Q_INVOKABLE void postDownload(const QString& url, const QString& savePath, const QVariantMap& postData, const QString& additionalobj) { if (m_currentDownload) { emit downloadCompleted(false, u8"已有进行中的下载"); return; } // 获取文件所在的目录路径 QFileInfo fileInfo(savePath); QString dirPath = fileInfo.absolutePath(); // 检查目录是否存在,如果不存在则创建 QDir dir; if (!dir.exists(dirPath)) { if (!dir.mkpath(dirPath)) { emit downloadCompleted(false, u8"无法创建目录"); cleanup(); return; } } // 创建目标文件 m_downloadFile = new QFile(savePath, this); if (!m_downloadFile->open(QIODevice::WriteOnly)) { emit downloadCompleted(false, u8"无法创建文件"); cleanup(); return; } QUrl u(url); // 配置 HTTPS QNetworkRequest request(u); QSslConfiguration sslConfig = request.sslConfiguration(); sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone); // 跳过证书验证 request.setSslConfiguration(sslConfig); // 构建 POST 数据(JSON 格式示例) QJsonDocument jsonDoc(QJsonObject::fromVariantMap (postData)); QByteArray postBody = jsonDoc.toJson(); // 发送请求 request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); m_currentDownload = manager.post(request, postBody); // 连接信号 connect(m_currentDownload, &QNetworkReply::readyRead, [this](){ m_downloadFile->write(m_currentDownload->readAll()); }); connect(m_currentDownload, &QNetworkReply::downloadProgress, [this,additionalobj](qint64 bytesReceived, qint64 bytesTotal){ m_downloadProgress = bytesTotal > 0 ? bytesReceived / (double)bytesTotal : 0; emit downloadProgressChanged(m_downloadProgress,additionalobj); }); connect(m_currentDownload, &QNetworkReply::finished, [this,additionalobj](){ if (m_downloadFile) { m_downloadFile->flush(); m_downloadFile->close(); } QVariant statusCodeVariant = m_currentDownload->attribute(QNetworkRequest::HttpStatusCodeAttribute); if (statusCodeVariant.isValid()) { int statusCode = statusCodeVariant.toInt(); qDebug() << "HTTP Status Code:" << statusCode; } bool success = !m_currentDownload->error(); QString message = success ? additionalobj : m_currentDownload->errorString(); if (success) { // 验证文件完整性 QFileInfo fi(m_downloadFile->fileName()); qint64 expectedSize = m_currentDownload->header( QNetworkRequest::ContentLengthHeader).toLongLong(); if (fi.size() != expectedSize && expectedSize > 0) { success = false; message = "文件不完整"; } } cleanup(); emit downloadCompleted(success, message.toUtf8()); }); } Q_INVOKABLE void postUpload(const QString& url, const QString& filePath, const QString& remotePath, const QString& additionalobj) { if (m_currentDownload) { // 复用同一个网络管理器,保持单请求 emit uploadCompleted(false, u8"已有进行中的传输"); return; } // 准备要上传的文件 QFile *uploadFile = new QFile(filePath, this); if (!uploadFile->open(QIODevice::ReadOnly)) { emit uploadCompleted(false, u8"无法打开文件"); uploadFile->deleteLater(); return; } // 创建多部分数据 QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType, this); // 添加文件部分 QHttpPart filePart; filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(QString("form-data; name=\"file\"; filename=\"%1\"") .arg(remotePath + QFileInfo(filePath).fileName()))); filePart.setBodyDevice(uploadFile); uploadFile->setParent(multiPart); // 文件对象由multiPart管理生命周期 multiPart->append(filePart); QUrl u(url); QNetworkRequest request(u); // 配置HTTPS QSslConfiguration sslConfig = request.sslConfiguration(); sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone); request.setSslConfiguration(sslConfig); // 发送请求 m_currentDownload = manager.post(request, multiPart); multiPart->setParent(m_currentDownload); // 由reply管理multiPart生命周期 // 连接进度信号 connect(m_currentDownload, &QNetworkReply::uploadProgress, [this, additionalobj](qint64 bytesSent, qint64 bytesTotal){ m_uploadProgress = bytesTotal > 0 ? bytesSent / (double)bytesTotal : 1; emit uploadProgressChanged(m_uploadProgress, additionalobj); // 带附加参数 }); // 处理完成信号 connect(m_currentDownload, &QNetworkReply::finished, [this, additionalobj](){ bool success = (m_currentDownload->error() == QNetworkReply::NoError); QString message = success ? u8"上传成功" : m_currentDownload->errorString(); cleanup(); emit uploadCompleted(success, additionalobj); }); } double downloadProgress() const { return m_downloadProgress; } double uploadProgress() const { return m_uploadProgress; } signals: // 下载相关信号 void downloadProgressChanged(double progress,const QString& additional); void downloadCompleted(bool success, const QString& message); // 上传相关信号(原有) void uploadProgressChanged(double progress ,const QString& additional); void uploadCompleted(bool success, const QString& message); private: explicit FileTransfer(QObject* parent = nullptr) : QObject(parent), m_downloadProgress(0), m_uploadProgress(0), m_currentDownload(nullptr), m_downloadFile(nullptr) {} QNetworkAccessManager manager; double m_downloadProgress; double m_uploadProgress; QNetworkReply* m_currentDownload; QFile* m_downloadFile; void cleanup() { if (m_downloadFile) { m_downloadFile->deleteLater(); m_downloadFile = nullptr; } if (m_currentDownload) { m_currentDownload->deleteLater(); m_currentDownload = nullptr; } m_downloadProgress = 0; } }; #endif // FILETRANSFER_H