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