Qt5.8用HTTP实现文件上传和下载(带进度条)

Qt5.8用HTTP实现文件上传和下载(带进度条)

本文基于Qt5.8利用HTTP协议实现文件的上传和下载。 本人所使用的HTTP服务器端的操作系统为Linux(Ubuntu),编写QT代码的客户端的操作系统为Windows.

重要声明: 由于QT5.4版本之前和之后所提供的的类的差别非常大,所以请参考本文的读者确保您自己的Qt版本>=5.4。我们主要使用的类QNetWorkAccessManager从5.4版本才开始有。

HTTP服务器(即Apache2)的详细配置可在本人原创的另一篇名为“Ubuntu16.04系统中配置ParaviewWeb5.3+Apache2”的博客中查看(http://blog.csdn.net/timothy93bp/article/details/77509164)。

我的HTTP服务器的用户名为peng, 密码为123456,ip地址为192.168.1.166, HTTP服务器的根目录(即Apache2当前激活的虚拟主机所定义的存放网页文件的目录)为/home/peng/http

  • 1. 与FTP的不同
  • 2. UI界面
  • 3. 修改.pro文件
  • 4. 头文件代码
  • 5. 源文件代码(上传,下载,进度条)
  • 6. PHP脚本代码

1. 与FTP的不同

用FTP上传和下载的代码可在本人原创的另一篇名为“Qt5.8用FTP实现文件上传和下载(带进度条)”的博客中查看。(http://blog.csdn.net/timothy93bp/article/details/77575079)

使用HTTP不存在考虑内网和外网的问题,但是代码比FTP稍微有点复杂。

HTTP下载的代码与FTP基本相同,但是HTTP上传的代码与FTP的不同主要体现在上传时的请求URL。因为用HTTP上传时,HTTP服务器端需要有一个PHP脚本来响应客户端请求,接收数据并写入文件(如名为upload.php),才能实现上传。

但是HTTP可以实现上传文件到服务器端的某一远程创建的目录中,目录名称由用户指定。若该目录在服务器端已经存在,则直接将文件保存在该目录中;若用户指定名称的目录在服务器中不存在,先远程在服务器上创建该目录,再往该目录中写入文件。这个过程也是由一个PHP脚本实现(如名为createFolder.php)。

所有的PHP脚本都应该放在服务器端,具体是在Apache2当前所激活的虚拟主机定义的存放网页文件的目录中。如该例中,PHP脚本都应该位于/home/peng/http中。

Qt5.8用HTTP实现文件上传和下载(带进度条)_第1张图片

2. UI界面

本程序的UI界面如下:

Qt5.8用HTTP实现文件上传和下载(带进度条)_第2张图片

文本编辑框中输入的是上传到服务器或者下载到本地之后,文件所要保存的名字, 该控件的objectName为“lineEdit“。”FTP上传”的按钮的objectName为“uploadButton“, “FTP下载”的按钮的objectName为“downloadButton“。

3. 修改.pro文件

首先,为了使用关于网络的类,我们首先要在.pro文件中加入一行:QT += network

//FTP.pro的内容

#-------------------------------------------------
#
# Project created by QtCreator 2017-08-25T14:00:00
#
#-------------------------------------------------

QT       += core gui
QT       += network

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = HTTP
TEMPLATE = app

# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0


SOURCES += main.cpp\
        mainwindow.cpp

HEADERS  += mainwindow.h

FORMS    += mainwindow.ui

4. 头文件代码

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_uploadButton_clicked();
    void on_downloadButton_clicked();
    void readContent();
    void replyFinished(QNetworkReply*);
    void loadError(QNetworkReply::NetworkError);
    void loadProgress(qint64 bytesSent,qint64 bytesTotal);

private:
    Ui::MainWindow *ui;
    QNetworkReply *reply;
    QProgressBar *progressBar;
    QFile *file;
};

#endif // MAINWINDOW_H

4. 源文件代码

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_uploadButton_clicked()    //上传文件
{
    file = new QFile("C:/Users/Administrator/Desktop/test.jpg");
    file->open(QIODevice::ReadOnly);

    QNetworkAccessManager *accessManager1 = new QNetworkAccessManager(this);  //在服务器上创建目录
    accessManager1->setNetworkAccessible(QNetworkAccessManager::Accessible);
    QByteArray data;
    QUrl url1("http://192.168.1.166:80/createFolder.php?foldername=upload");
    QNetworkRequest request1(url1);
    request1.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/octet-stream"));
    accessManager1->post(request1, data);

    QNetworkAccessManager *accessManager2 = new QNetworkAccessManager(this);    //往该目录中上传文件
    accessManager2->setNetworkAccessible(QNetworkAccessManager::Accessible);
    QByteArray byte_file = file->readAll();
    QUrl url2("http://192.168.1.166:80/upload.php?foldername=upload&filename="+ui->lineEdit->text()+".jpg");    //如这里指定的上传文件至HTTP服务器目录中的upload目录中
    QNetworkRequest request2(url2);
    request2.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream");
    reply = accessManager2->post(request2, byte_file);

    progressBar = new QProgressBar();
    progressBar->setValue(0);
    progressBar->show();

    connect(accessManager2,SIGNAL(finished(QNetworkReply*)),this,SLOT(replyFinished(QNetworkReply*)));
    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(loadError(QNetworkReply::NetworkError)));
    connect(reply, SIGNAL(uploadProgress(qint64 ,qint64)), this, SLOT(loadProgress(qint64 ,qint64)));
}

void MainWindow::on_downloadButton_clicked()    //下载文件
{
    file = new QFile(QApplication::applicationDirPath() + "/" + ui->lineEdit->text() + ".jpg");
    file->open(QIODevice::WriteOnly);

    QNetworkAccessManager *accessManager = new QNetworkAccessManager(this);
    accessManager->setNetworkAccessible(QNetworkAccessManager::Accessible);
    QUrl url("http://192.168.1.166:80/test.jpg");

    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream");
    reply = accessManager->get(request);

    progressBar = new QProgressBar();
    progressBar->setValue(0);
    progressBar->show();

    connect((QObject *)reply, SIGNAL(readyRead()), this, SLOT(readContent()));
    connect(accessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(loadError(QNetworkReply::NetworkError)));
    connect(reply, SIGNAL(downloadProgress(qint64 ,qint64)), this, SLOT(loadProgress(qint64 ,qint64)));
}

void MainWindow::readContent()    //下载时向本地文件中写入数据
{
    file->write(reply->readAll());
}

void MainWindow::replyFinished(QNetworkReply*)    //删除指针,更新和关闭文件
{
    if(reply->error() == QNetworkReply::NoError)
        {
            reply->deleteLater();
            file->flush();
            file->close();
        }
        else
        {
            QMessageBox::critical(NULL, tr("Error"), "Failed!!!");
        }
}

void MainWindow::loadProgress(qint64 bytesSent, qint64 bytesTotal)    //更新进度条
{
       qDebug() << "loaded" << bytesSent << "of" << bytesTotal;
       progressBar->setMaximum(bytesTotal); //最大值
       progressBar->setValue(bytesSent);  //当前值
}

void MainWindow::loadError(QNetworkReply::NetworkError)    //传输中的错误输出
{
     qDebug()<<"Error: "<error();
}

6. PHP脚本代码

  • 1) 在服务器上创建目录的PHP脚本

//createFolder.php

 
    $foldername =$_GET['foldername'];

    if (!file_exists($foldername)){
        mkdir ($foldername);
        echo 'succeed in creating folder!';
    } 
    else {
        echo 'This folder has existed!';
    }

?>

“foldername”为用户指定的文件名,比如这里是“upload”。

  • 2) 往服务器的该目录下写入文件的PHP脚本

//upload.php


 $content = file_get_contents('php://input');
 $foldername = $_GET["foldername"];
 $filename = $_GET["filename"];
 $fp = fopen($foldername."/".$filename,'w+');
 fwrite($fp, $content, strlen($content));
 fclose($fp);
?>

“filename”为用户在UI的lineEdit中输入的文件名+后缀名,也就是文件要存放在服务器上的名字。

以上代码为全部代码,可以直接在客户端的QT上创建一个名为“HTTP”的基于MainWindow的新项目,然后按上述步骤建立ui界面,修改.pro文件,再往.h和.cpp文件中完全复制以上的代码,最后在服务器端http目录中创建“createFolder.php”和“upload.php”文件,并完全复制粘贴以上的代码,点击运行即可。

你可能感兴趣的:(C++代码,http,文件上传,文件下载,Qt5-8,Ubuntu)