Qt项目实战四:FTP上传/下载工具

实现FTP Client功能

ubuntu搭建ftp服务器

1、选用vsftpd为我们的ftp服务器,端口号默认为21
安装:~$ sudo apt‐get install vsftpd
2、配置:~$ sudo gedit /etc/vsftpd.conf
3、 几个重要的参数:

anonymous_enable=NO 是否支持匿名访问

local_enable=YES 是否允许本地用户登录

write_enable=YES 是否给客户端写的权限 (默认只读)

4、几个重要的命令

 ~$ sudo /etc/init.d/vsftpd restart 重启vsftp服务 (ubuntu 18)

~$ ps ‐ef | grep ftp 查看ftp服务器是否启动

~$ sudo netstat ‐utlpn | grep vsftp 查看vsftp状态及端口号

PS:如果想修改端口号(建议不要修改)
1、编辑/etc/vsftpd/vsftpd.conf 文件,在该配置文件中添加此行:listen_port=6666
2、编辑/etc/services 文件,将其中的 ftp 21/tcp 改为 ftp 21/tcp 改为 ftp 6666/tcp

QT实现ftp的客户端

通过该项目学会
QNetworkAccessManager上传和下载,对N多协议都支持;
QNetworkAccessManager 自己会新建线程 不用使用QThread
如果不需要遍历FtpServer目录可以直接使用QNetworkAccesssManager

  • QUrl
  • QNetworkAccessManager
  • QNetworkReply

完整的ftp地址



完整代码

  • ftpAccessManager.h
#ifndef FTPACCESSMANAGER_H
#define FTPACCESSMANAGER_H

#include <QObject>
#include <QUrl>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QFile>
#include <QFileInfo>
#include <QDebug>
#include <QEvent>

class ftpAccessManager : public QObject
{
    Q_OBJECT
public:
    explicit ftpAccessManager(QObject *parent = nullptr);
    virtual bool event(QEvent *event);

public:
    // 设置端口
    void setHostPortInfo(const QString &host, quint16 prot =21);
    void setUserPwdInfo(const QString &userName, const QString &pwd);

    // 下载路径
    void putFileFromClent(const QString &fileName, const QString &path);
    void getFileFromServer(const QString &fileName, const QString &path);

signals:
    /* 以下信号上传给界面 */
    void uploadProgressSignal(qint64, qint64);
    void downloadProgressSignal(qint64, qint64);
    void netErrorSignal(QNetworkReply::NetworkError);

private slots:
    //上传时的槽
    void uploadProgressSlot(qint64, qint64);
    void uploadFinishedSlot();
    void uploadErrorSlot(QNetworkReply::NetworkError);

    //下载时的槽
    void downloadProgressSlot(qint64, qint64);
    void downloadFinishedSlot();
    void downloadErrorSlot(QNetworkReply::NetworkError);

private:
    QUrl murl;
    QNetworkAccessManager mNetAccMgr;

    QFile *putFileData = nullptr;           //上传数据的文件指针
    QFile *getFileData = nullptr;

    QNetworkReply *putNetReply;            //上传的网络应答  QNetworkRequest请求
    QNetworkReply *getNetReply;            //下载数据的网络



};

#endif // FTPACCESSMANAGER_H

  • ftpAccessManager.cpp
#include "ftpAccessManager.h"

ftpAccessManager::ftpAccessManager(QObject *parent)
    : QObject{parent}
{
    murl.setScheme("ftp"); // 设置协议
}

/*
 * 设置FTP主机地址信息,包括Ip地址和端口号
*/
void ftpAccessManager::setHostPortInfo(const QString &host, quint16 prot)
{
    murl.setHost(host);
    murl.setPort(prot);

}

/*
 * 设置FTP用户密码信息
*/
void ftpAccessManager::setUserPwdInfo(const QString &userName, const QString &pwd)
{
    murl.setUserName(userName);
    murl.setPassword(pwd);
}

/*
 * 上传文件
 * 参数1:本地文件(带路径)    参数2:服务器端文件(带路径) <服务器路径必须带上文件名,不然服务器不知道写什么样的文件>
*/
void ftpAccessManager::putFileFromClent(const QString &clientFile, const QString &serverPath)
{
    putFileData = new QFile(clientFile, this);
    QString serverFileNamePath = serverPath + "/" +
            QFileInfo(clientFile).fileName(); //路径+文件拼接,保证服务器端写入的文件和本地文件同名

    //step1 :: setUrl
    murl.setPath(serverFileNamePath);

    //step2:打开文件 把文件读入到网络流发出去
    if(putFileData->open(QIODevice::ReadOnly))
    {
        //step3:upload 上传
        putNetReply = mNetAccMgr.put(QNetworkRequest(murl), putFileData);

        //step4:关联信号与槽
        connect(putNetReply, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgressSlot(qint64, qint64)));
        connect(putNetReply, SIGNAL(finished()), this, SLOT(uploadFinishedSlot()));
        connect(putNetReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(uploadErrorSlot(QNetworkReply::NetworkError)));
    }
    else
    {
        delete putFileData;
        putFileData = nullptr;
    }
}

/*
 * 下载文件
 * 参数1:需要写入的本地文件(带路径 不带路径则为当前目录)    参数2:服务器端的路径
*/
void ftpAccessManager::getFileFromServer(const QString &saveNameWithPath, const QString &downloadPath)
{
    getFileData = new QFile(saveNameWithPath, this);

    //step1 :: setUrl
    murl.setPath(downloadPath);

    if(getFileData->open(QIODevice::WriteOnly | QFile::Truncate))
    {
        getNetReply = mNetAccMgr.get(QNetworkRequest(murl));
        //step4 :
        connect(getNetReply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgressSlot(qint64, qint64)));
        connect(getNetReply, SIGNAL(finished()), this, SLOT(downloadFinishedSlot()));
        connect(getNetReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(downloadErrorSlot(QNetworkReply::NetworkError)));
    }
    else
    {
        delete getFileData;
        getFileData = nullptr;
    }
}


void ftpAccessManager::uploadProgressSlot(qint64 bytesSent, qint64 bytesTotal)
{
    emit uploadProgressSignal(bytesSent, bytesTotal);
    //qDebug() << "uploadProgressSlot" << bytesSent << bytesTotal;
}



void ftpAccessManager::uploadFinishedSlot()
{
    qDebug() << "uploadFinishedSlot" ;

    putNetReply->deleteLater();
    delete putFileData;
    putFileData = nullptr;
}

void ftpAccessManager::uploadErrorSlot(QNetworkReply::NetworkError errorCode)
{
    putNetReply->deleteLater();
    delete putFileData;
    putFileData = nullptr;

    switch (errorCode)
    {
    case QNetworkReply::HostNotFoundError :
        qDebug() << "HostNotFoundError";
        break;
    case QNetworkReply::ConnectionRefusedError :
        qDebug() << "ConnectionRefusedError";
        break;
    default:
        qDebug() << "orther error" << errorCode;
        break;
    }

    emit netErrorSignal(errorCode);
}

void ftpAccessManager::downloadProgressSlot(qint64 bytesSent, qint64 bytesTotal)
{

    emit downloadProgressSignal(bytesSent, bytesTotal);
    getFileData->write(getNetReply->readAll());         //写文件到磁盘
}


void ftpAccessManager::downloadFinishedSlot()
{
    qDebug() << "downloadFinishedSlot";

    getNetReply->deleteLater();
    delete getFileData;
    getFileData = nullptr;
}

void ftpAccessManager::downloadErrorSlot(QNetworkReply::NetworkError errorCode)
{
    qDebug() << "downloadErrorSlot" << errorCode;

    getNetReply->deleteLater();
    delete getFileData;
    getFileData = nullptr;

    emit netErrorSignal(errorCode);
}

/* 演示deleteLater什么时候生效 */
bool ftpAccessManager::event(QEvent *event)
{
    qDebug()<<"event" << event->isAccepted();
    return true;
}

  • widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QMessageBox>
#include <QFileDialog>
#include "ftpAccessManager.h"


QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButtonDownload_clicked();

    void on_pushButtonUpload_clicked();

    void uploadProgressSlot(qint64, qint64);
    void downloadProgressSlot(qint64, qint64);
    void netErrorSlot(QNetworkReply::NetworkError);
private:
    bool getHostInfoFromUi();

private:
    Ui::Widget *ui;
    ftpAccessManager mFtpAccMgr;
    QString ftpServerHost;
    qint16  ftpServerPort;
    QString ftpServerUsr;
    QString ftpServerPasswd;
};
#endif // WIDGET_H

  • widget.cpp
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect(&mFtpAccMgr, SIGNAL(uploadProgressSignal(qint64,qint64)),
            this, SLOT(uploadProgressSlot(qint64,qint64)));

    connect(&mFtpAccMgr, SIGNAL(downloadProgressSignal(qint64,qint64)),
            this, SLOT(downloadProgressSlot(qint64,qint64)));

    connect(&mFtpAccMgr, SIGNAL(netErrorSignal(QNetworkReply::NetworkError)),
            this, SLOT(netErrorSlot(QNetworkReply::NetworkError)));
}

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


bool Widget::getHostInfoFromUi()
{
    ftpServerHost = ui->lineEditHostAddress->text();
    ftpServerPort = ui->lineEditPort->text().toInt();
    ftpServerUsr = ui->lineEditUsrName->text();
    ftpServerPasswd = ui->lineEditPassWord->text();

    if(ftpServerHost.isEmpty() || ftpServerUsr.isEmpty()
            || ftpServerPasswd.isEmpty())
    {
        QMessageBox::warning(this, "Host Error", "Please input Host Info:Host Usr PWD");
        return false;
    }
    return true;
}

void Widget::on_pushButtonUpload_clicked()
{
    if(! getHostInfoFromUi())
        return;

    mFtpAccMgr.setHostPortInfo(ftpServerHost, ftpServerPort);
    mFtpAccMgr.setUserPwdInfo(ftpServerUsr, ftpServerPasswd);

    QString clientFile = QFileDialog::getOpenFileName(this,
                                                      QString::fromLocal8Bit("选择需要上传的文件"));
    if(clientFile.isEmpty())
    {
        QMessageBox::warning(this, "upload error", "please select One file");
        return;
    }


    QString serverPath = ui->lineEditUploadPath->text();
    if(serverPath.isEmpty())
    {
        QMessageBox::warning(this, "upload error", "please select correct ftp path");
        return;
    }

    mFtpAccMgr.putFileFromClent(clientFile, serverPath);
}


void Widget::on_pushButtonDownload_clicked()
{
    if(! getHostInfoFromUi())
        return;

    QString downloadPath = ui->lineEditDownloadPath->text();

    mFtpAccMgr.setHostPortInfo(ftpServerHost, ftpServerPort);
    mFtpAccMgr.setUserPwdInfo(ftpServerUsr, ftpServerPasswd);

    QString targetFileName = QFileInfo(downloadPath).fileName();

    if(targetFileName.isEmpty())
        return;

    QString saveNameWithPath = QFileDialog::getSaveFileName(this,
                                                            QString::fromLocal8Bit("保存为..."),
                                                            targetFileName,
                                                            "");


    mFtpAccMgr.getFileFromServer(saveNameWithPath, downloadPath);
}

void Widget::uploadProgressSlot(qint64 bytesReceived, qint64 bytesTotal)
{
    //    ui->progressBarUpload->setMaximum(bytesTotal);
    //    ui->progressBarUpload->setValue(bytesReceived);
    //解决文件大小大于0x7fffffff情况 > int
    qint32 fileSize = (qint32)(bytesReceived / (1024 * 1024));  //换成M单位
    if(bytesReceived > 0 && fileSize == 0)
    {
        fileSize = 1;
    }

    qint32 totalSize = (qint32)(bytesTotal / (1024 * 1024));
    if(bytesTotal > 0 && totalSize == 0)
    {
        totalSize = 1;
    }

    ui->progressBarUpload->setMaximum(totalSize);     //这句话一定要写在setValue前面
    ui->progressBarUpload->setValue(fileSize);
}

void Widget::downloadProgressSlot(qint64 bytesReceived, qint64 bytesTotal)
{
    //    ui->progressBarDownload->setMaximum(bytesTotal);
    //    ui->progressBarDownload->setValue(bytesReceived);
    qint32 fileSize = (qint32)(bytesReceived / (1024 * 1024));
    if(bytesReceived > 0 && fileSize == 0)
    {
        fileSize = 1;
    }

    qint32 totalSize = (qint32)(bytesTotal / (1024 * 1024));
    if(bytesTotal > 0 && totalSize == 0)
    {
        totalSize = 1;
    }

    ui->progressBarDownload->setMaximum(totalSize);
    ui->progressBarDownload->setValue(fileSize);
}

void Widget::netErrorSlot(QNetworkReply::NetworkError errorCode)
{
    //显示在状态栏里
}

需要在pro文件中添加QT += network

  • 5
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

√沫影

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

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

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

打赏作者

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

抵扣说明:

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

余额充值