QT实现Ftp客户端的三种方法及工程实例

时间:2024-03-05 18:53:16

1.Qt项目中实现的FTP传输功能的三种方式

(1)QFtp

     QFtp 是 Qt4 中专门负责 FTP 传输的类,包括创建目录、删除目录、删除文件、获取文件列表、上传、下载等等常规操作。

     注意:QT5中已经移除,如果需要用需要自己添加QFtp类文件。

(2)QNetworkAccessManager

     是 Qt 专门负责网络请求的模块,包含了 http 的 post、get、put,put 用来 Qt5 实现 FTP 上传功能,get 用来实现下载功能,仅仅只能上传下载,功能较少。

(3)POCO FTPClientSession

     FTPClientSession 是 POCO 中网络模块里负责实现 FTP 的类,接口如下,POCO 是目前最流行的 C++ 轻量级封装库之一,里面包含了很多常用的封装库,不是只有FTP功能。

     注意:其属于第三方库

2.三种方式的区别

(1)QFtp:

简单易用:QFtp 是Qt提供的一个简单的FTP客户端类,它提供了FTP操作的基本功能,并且使用相对简单。

同步操作:QFtp 主要基于同步操作,这意味着代码更直观,容易理解。

缺点:

不支持FTP over SSL/TLS:QFtp 不支持通过SSL/TLS加密的FTP连接,这在需要安全传输时是一个限制。

不支持异步操作:对于大型文件传输或需要同时处理多个FTP请求的应用,同步操作可能会导致界面冻结或性能问题。

在Qt5中,QFtp 已被标记为弃用,如果用要单独加入QFtp类

(2)QNetworkAccessManager

优点:简单,集成度高;

异步操作:QNetworkAccessManager 支持异步操作,这使得它更适合处理大型文件传输或多个并发请求。

支持HTTPS:与QFtp 不同,QNetworkAccessManager 支持通过HTTPS进行安全传输。

灵活性强:你可以使用它来发送和接收HTTP请求,不仅限于FTP。

缺点:

使用QNetworkAccessManager 实现FTP功能需要更多的代码和设置,相比QFtp 来说更复杂。

QNetworkAccessManager虽然也支持 FTP 通信,但其主要侧重于 HTTP 请求处理,FTP 功能相对较弱。

(3)FTPClientSession

优点:

专业的FTP实现:FTPClientSession(需要引入第三方库),提供了比QFtp 和 QNetworkAccessManager 更全面和专业的FTP功能。

支持FTP over SSL/TLS:通常,专业的FTP客户端库会支持FTP over SSL/TLS,这对于安全传输是必要的。

异步和同步操作:专业的FTP客户端库通常支持异步和同步操作,这使得它们更灵活。

缺点:

需要第三方库:FTPClientSession 可能不是Qt标准库的一部分,这意味着你需要集成第三方库,这可能会增加项目的复杂性。

学习曲线:如果你之前没有使用过类似的库,可能需要一些时间来学习和理解它的API和工作方式。

(4)总结

对于简单的FTP任务,并且不需要加密或异步操作,QFtp 可能是一个不错的选择。

对于需要异步操作和/或HTTPS支持的项目,QNetworkAccessManager 是一个合理的选择。尽管它的FTP功能有限,但它通常能满足大多数基本需求。

对于需要全面和专业的FTP功能,特别是需要FTP over SSL/TLS支持的项目,使用像FTPClientSession 这样的专业FTP客户端库可能是最佳选择。

3.代码示例  

(1).采用QFtp库,qt5.12开发

#include "mainwindow.h"

#include "ui_mainwindow.h"

#include "qftp.h"

#include <QTextCodec>

#include <QFile>

#include <QTreeWidgetItem>

MainWindow::MainWindow(QWidget *parent) :

    QMainWindow(parent),

    ui(new Ui::MainWindow)

{

    ui->setupUi(this);

    ui->progressBar->setValue(0);

    connect(ui->fileList, &QTreeWidget::itemActivated,

            this, &MainWindow::processItem);

}

MainWindow::~MainWindow()

{

    delete ui;

}

void MainWindow::ftpCommandStarted(int)

{

    int id = ftp->currentCommand();

    switch (id)

    {

    case QFtp::ConnectToHost :

        ui->label->setText(tr("正在连接到服务器…"));

        break;

    case QFtp::Login :

        ui->label->setText(tr("正在登录…"));

        break;

    case QFtp::Get :

        ui->label->setText(tr("正在下载…"));

        break;

    case QFtp::Close :

        ui->label->setText(tr("正在关闭连接…"));

    }

}

void MainWindow::ftpCommandFinished(int, bool error)

{

    if(ftp->currentCommand() == QFtp::ConnectToHost) {

        if (error)

            ui->label->setText(tr("连接服务器出现错误:%1").arg(ftp->errorString()));

        else ui->label->setText(tr("连接到服务器成功"));

    } else if (ftp->currentCommand() == QFtp::Login) {

        if (error)

            ui->label->setText(tr("登录出现错误:%1").arg(ftp->errorString()));

        else {

            ui->label->setText(tr("登录成功"));

            ftp->list();

        }

    } else if (ftp->currentCommand() == QFtp::Get) {

        if(error)

            ui->label->setText(tr("下载出现错误:%1").arg(ftp->errorString()));

        else {

            ui->label->setText(tr("已经完成下载"));

            file->close();

        }

        ui->downloadButton->setEnabled(true);

    } else if (ftp->currentCommand() == QFtp::List) {

        if (isDirectory.isEmpty())

        {

            ui->fileList->addTopLevelItem(

                        new QTreeWidgetItem(QStringList()<< tr("<empty>")));

            ui->fileList->setEnabled(false);

            ui->label->setText(tr("该目录为空"));

        }

    } else if (ftp->currentCommand() == QFtp::Close) {

        ui->label->setText(tr("已经关闭连接"));

    }

}

// 连接按钮

void MainWindow::on_connectButton_clicked()

{

    ui->fileList->clear();

    currentPath.clear();

    isDirectory.clear();

    ui->progressBar->setValue(0);

    ftp = new QFtp(this);

    connect(ftp, &QFtp::commandStarted, this,

            &MainWindow::ftpCommandStarted);

    connect(ftp, &QFtp::commandFinished,

            this, &MainWindow::ftpCommandFinished);

    connect(ftp, &QFtp::listInfo, this, &MainWindow::addToList);

    connect(ftp, &QFtp::dataTransferProgress,

            this, &MainWindow::updateDataTransferProgress);

    QString ftpServer = ui->ftpServerLineEdit->text();

    QString userName = ui->userNameLineEdit->text();

    QString passWord = ui->passWordLineEdit->text();

    ftp->connectToHost(ftpServer, 21);

    ftp->login(userName, passWord);

}

void MainWindow::addToList(const QUrlInfo &urlInfo)

{

    // 注意:因为服务器上文件使用UTF-8编码,所以要进行编码转换,这样显示中文才不会乱码

    QString name = QString::fromUtf8(urlInfo.name().toLatin1());

    QString owner = QString::fromUtf8(urlInfo.owner().toLatin1());

    QString group = QString::fromUtf8(urlInfo.group().toLatin1());

    QTreeWidgetItem *item = new QTreeWidgetItem;

    item->setText(0, name);

    item->setText(1, QString::number(urlInfo.size()));

    item->setText(2, owner);

    item->setText(3, group);

    item->setText(4, urlInfo.lastModified().toString("yyyy-MM-dd"));

    QPixmap pixmap(urlInfo.isDir() ? "../myFTP/dir.png" : "../myFTP/file.png");

    item->setIcon(0, pixmap);

    isDirectory[name] = urlInfo.isDir();

    ui->fileList->addTopLevelItem(item);

    if (!ui->fileList->currentItem()) {

        ui->fileList->setCurrentItem(ui->fileList->topLevelItem(0));

        ui->fileList->setEnabled(true);

    }

}

void MainWindow::processItem(QTreeWidgetItem *item, int)

{

    // 如果这个文件是个目录,则打开

    if (isDirectory.value(item->text(0))) {

        // 注意:因为目录名称可能是中文,在使用ftp命令cd()前需要先进行编码转换

        QString name = QLatin1String(item->text(0).toUtf8());

        ui->fileList->clear();

        isDirectory.clear();

        currentPath += "/";

        currentPath += name;

        ftp->cd(name);

        ftp->list();

        ui->cdToParentButton->setEnabled(true);

    }

}

// 返回上级目录按钮

void MainWindow::on_cdToParentButton_clicked()

{

    ui->fileList->clear();

    isDirectory.clear();

    currentPath = currentPath.left(currentPath.lastIndexOf('/'));

    if (currentPath.isEmpty()) {

        ui->cdToParentButton->setEnabled(false);

        ftp->cd("/");

    } else {

        ftp->cd(currentPath);

    }

    ftp->list();

}

// 下载按钮

void MainWindow::on_downloadButton_clicked()

{

    // 注意:因为文件名称可能是中文,所以在使用get()函数前需要进行编码转换

    QString fileName = ui->fileList->currentItem()->text(0);

    QString name = QLatin1String(fileName.toUtf8());

    file = new QFile(fileName);

    if (!file->open(QIODevice::WriteOnly)) {

        delete file;

        return;

    }

    ui->downloadButton->setEnabled(false);

    ftp->get(name, file);

}

void MainWindow::updateDataTransferProgress(qint64 readBytes,qint64 totalBytes)

{

    ui->progressBar->setMaximum(totalBytes);

    ui->progressBar->setValue(readBytes);

}

(2)测试界面

(3)完整工程代码下载:https://download.csdn.net/download/xieliru/88906720