1 前言
在前面写完HTTP相关下载后,上传肯定也是少不了的,虽然平时我们上传用的少,但是也是一个不可或缺的功能,所以今天打算简单的讲讲Qt相关的Http上传功能。
公众号:Qt实战,各种开源作品、经验整理、项目实战技巧,专注Qt/C++软件开发,视频监控、物联网、工业控制、嵌入式软件、国产化系统应用软件开发。
公众号:Qt入门和进阶,专门介绍Qt/C++相关知识点学习,帮助Qt开发者更好的深入学习Qt。多位Qt元婴期大神,一步步带你从入门到进阶,走上财务自由之路。
官方店:https://shop114595942.taobao.com//
2 上传接口
有了前面的关于Qt网络的基础类的了解,下面的介绍大家肯定会一点就通!当然我们的上传同样是基于 QNetworkAccessManager 开发的, 大家可以回忆下在前面下载的章节中我们用到的是Get,如下:
QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
是不是很有印象,所以上传也就是对应的post,Qt提供的get只有一个方法,而post有多个重载方法,说明上传的方法有多种,看你自己需要哪一种,如下:
QNetworkReply *post(const QNetworkRequest &request, QIODevice *data)
QNetworkReply *post(const QNetworkRequest &request, const QByteArray &data)
QNetworkReply *post(const QNetworkRequest &request, QHttpMultiPart *multiPart)
每一个都是第二个参数不一样的,所以用到的方式也不一样,一般我们能用到的也就是第二个和第三个了,3是我比较推荐的使用方式,也是这次重点的介绍对象,也就是使用QHttpMultiPart 上传文件
3 程序介绍
基于QByteArray的上传, 我们先使用第二个方法来上传文件,服务端这边是我这边用python搭建的一个简单的本地测试服务器,所以大家注意客户端就行!
实例名称为HttpUpload, 下图是程序运行上传文件时的界面:
在URL地址编辑框里输入一个上传的网络URL地址,我这边是默认的本地地址,所以直接127.0.0.1即可,点击选择上传的文件按钮,在弹出的选择文件框中选择需要上传的文件,设置上传文件的路径后,单击上传按钮就可以开始上传文件到对应的服务端的目录下。进度条可以显示文件上传进度。
实例HttpUpload主界面是基于QWidget的窗口类HttpUpload,使用UI设计器设计界
面,HttpUpload 类的定义如下:
class HttpUpload : public QWidget
{
Q_OBJECT
public:
HttpUpload(QWidget *parent = nullptr);
~HttpUpload();
private slots:
void on_pushButton_selectUploadFile_clicked();
void on_pushButton_startUpload_clicked();
//自定义槽信号
void onUpLoadFinished();
void onUpLoadError(QNetworkReply::NetworkError errorCode);
void OnUploadProgress( qint64 bytesSent, qint64 bytesTotal );
private:
Ui::HttpUpload *ui;
QNetworkAccessManager * _pUploadManager = nullptr;
QNetworkReply * _pReply = nullptr;
};
#endif // HTTPUPLOAD_H
4 获取上传文件及动图
要上传文件,先在窗口上的 URL编辑框 里输入上传的文件地址(可以使用Ctrl+V组合键粘贴URL地址),或者点击 选择上传的文件按钮,选择需要上传的文件, 选择上传的文件按钮代码如下:
void HttpUpload::on_pushButton_selectUploadFile_clicked()
{
QFileDialog *fileDialog = new QFileDialog(this);
//定义文件对话框标题
fileDialog->setWindowTitle(QStringLiteral("选中文件"));
//设置默认文件路径
fileDialog->setDirectory(".");
//设置文件过滤器
fileDialog->setNameFilter(tr("File(*.*)"));
//设置可以选择多个文件,默认为只能选择一个文件QFileDialog::ExistingFiles
fileDialog->setFileMode(QFileDialog::ExistingFiles);
//设置视图模式
fileDialog->setViewMode(QFileDialog::Detail);
//打印所有选择的文件的路径
QStringList fileNames;
if (fileDialog->exec()) {
fileNames = fileDialog->selectedFiles();
}
//如果选择的文件不为空则显示到界面上
if(!fileNames.isEmpty())
{
ui->lineEdit->setText(fileNames.first());
}
}
效果图如下:
选择相应文件后,单击 开始上传 按钮开始上传过程, 开始上传 按钮的响应代码如下:
5 QByteArray上传方式,仅供代码参考
void HttpUpload::on_pushButton_startUpload_clicked()
{
if(_pUploadManager == nullptr)
{
_pUploadManager = new QNetworkAccessManager(this);
}
QString uploadFileName = ui->lineEdit->text();
QFile file(uploadFileName);
if(!file.open(QIODevice::ReadOnly))
{
qWarning("file open fail");
return;
}
QByteArray byteFileData = file.readAll();
file.close();
QString uploadUrl = ui->lineEdit_UploadURL->text();
QUrl url(uploadUrl+"?filename="+file.fileName());
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream");
_pReply = _pUploadManager->post(request, byteFileData);
connect(_pReply, &QNetworkReply::finished,this, &HttpUpload::onUpLoadFinished);
connect(_pReply, SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(onUpLoadError(QNetworkReply::NetworkError)));
connect(_pReply, SIGNAL(uploadProgress(qint64 ,qint64)), this, SLOT(OnUploadProgress(qint64 ,qint64)));
}
这种方式要有对应的服务端接收,一般模式是采用表单方式,所以很少支持这种,我写的也不支持,所以支持显示一下实现代码,具体使用还是要看QHttpMultiPart 强烈推荐
6 基于QHttpMultiPart实现的上传及动态效果图
下面是基于 QHttpMultiPart 实现代码:
void HttpUpload::on_pushButton_startUpload_clicked()
{
if(_pUploadManager == nullptr)
{
_pUploadManager = new QNetworkAccessManager(this);
}
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QString uploadFileName = ui->lineEdit->text();
QFileInfo fileInfo(uploadFileName);
QString fileName = fileInfo.fileName();
QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/png"));
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(QString("form-data; name=\"uploadfile\";filename=\"%1\"").arg(fileName)));
QFile *file = new QFile(uploadFileName);
file->open(QIODevice::ReadOnly);
imagePart.setBodyDevice(file);
file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart
multiPart->append(imagePart);
QString urlServerStr = ui->lineEdit_UploadURL->text();
QUrl url(urlServerStr);
QNetworkRequest request(url);
_pReply = _pUploadManager->post(request, multiPart);
multiPart->setParent(_pReply); // delete the multiPart with the reply
connect(_pReply, &QNetworkReply::finished,this, &HttpUpload::onUpLoadFinished);
connect(_pReply, &QNetworkReply::uploadProgress, this, &HttpUpload::OnUploadProgress);
}
看上传效果图:
因为我是本地搭建的HTTP文件服务器, 服务端指定位置上图的文件夹位置,所以可以看到,上传成功后,是有响应的,而且文件也是成功被上传到指定文件夹。