现在Qt主推使用 QNetworkAccessManager 可以实现 Ftp 的上传/下载功能(参考:Qt之FTP上传/下载),但有些原本 QFtp 有的功能 QNetworkAccessManager 却没有提供,例如:list、cd、remove、mkdir、rmdir、rename 等。这种情况下,就不得不使用 QFtp,值得庆幸的是 QFtp 一直在维护,只需要下载源码自行编译即可使用。而我恰好需要使用到list。所以需要重新编译QFtp。
一、环境搭建
QFtp
下载
从 GitHub 下载 QFtp:
配置
注意:第一次使用CONFIG -= static CONFIG+=shared
第二次使用CONFIG += static CONFIG-=shared
编译后的库才会齐全。
该库的链接为:https://download.csdn.net/download/weixin_41882459/12104260
在pro文件中完成此两项配置
文件的拷贝
目录下生成的*.dll动态库文件(Qt5Ftp.dll、Qt5Ftpd.dll)复制到C:\Qt\Qt5.10.1\5.10.1\msvc2015\bin目录下。
目录下生成的*.lib和*.prl静态库文件复制到 C:\Qt\Qt5.10.1\5.10.1\msvc2015\lib
目录下的qftp.h和qurlinfo.h复制到 C:\Qt\Qt5.10.1\5.10.1\msvc2015\include\QtNetwork目录下。
在C:\Qt\Qt5.10.1\5.10.1\msvc2015\include\QtNetwork目录中新建一个没有后缀名的QFtp文件
然后用记事本写入#include ”qftp.h”
使用
在 pro 中添加 QFtp 库:
CONFIG(debug, debug|release) {
LIBS += -lQt5Ftpd
} else {
LIBS += -lQt5Ftp
}
例如,如果要连接并登录到 FTP 服务器,这是简单的实现:
#include <QFtp>
// ...
QFtp *ftp = new QFtp(parent);
ftp->connectToHost("192.168.***.***", 2121); // 主机:192.168.***.*** 端口号:2121
ftp->login("dell-T", "123456"); // 用户名:dell-T 密码:123456
// ...
二、使用方法
使用流程
1、连接ftp到服务器
2、下载或上传
3、关闭
主要代码如下
ftp连接到服务器
//ftp客户端连接
ftpClient=new QFtp(this);
// 当每条命令开始执行时发出相应的信号
connect(ftpClient,SIGNAL(commandStarted(int)),this,SLOT(ftpCommandStarted(int)));
connect(ftpClient,SIGNAL(commandFinished(int,bool)),this,SLOT(ftpCommandFinished(int,bool)));
connect(ftpClient,SIGNAL(listInfo(QUrlInfo)),this,SLOT(addToList(QUrlInfo)));
connect(ftpClient,SIGNAL(dataTransferProgress(qint64,qint64)),this,SLOT(updateDataTransferProgress(qint64,qint64)));
connect(ftpClient,SIGNAL(stateChanged(int)),this,SLOT(ftpStateChanged(int)));
ftpClient->setTransferMode(QFtp::Active);
ftpClient->connectToHost(ui->FTPServerLineEdit->text(),ui->ftpServerPortSpinBox->value());
ftpClient->login(ui->FTPIDLineEdit->text(),ui->FTPPasswordLineEdit->text());
ftp下载
void MainWindow::dealFtpDownloadSignal()
{
QFileInfo fi(globalCurrentFile);
ui->downLoadLabel->setText(fi.fileName()+"下载进度");
ftpClient->get(fi.fileName(),globalCurrentDownloadFile);
}
下载进度条更新
void MainWindow::updateDataTransferProgress(qint64 bytesReceived, qint64 bytesTotal)
{
ui->progressBar->setMaximum(bytesTotal);
ui->progressBar->setValue(bytesReceived);
}
ftp状态改变
void MainWindow::ftpStateChanged(int state)
{
switch (state) {
case QFtp::Unconnected: {
setInsertTextColor(Qt::red);
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+tr(":没有连接到主机"));
break;
}
case QFtp::HostLookup: {
setInsertTextColor(Qt::black);
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+tr(":正在进行主机名查找..."));
break;
}
case QFtp::Connecting: {
setInsertTextColor(Qt::black);
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+tr(":正在尝试连接到主机..."));
break;
}
case QFtp::Connected: {
setInsertTextColor(Qt::black);
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+tr(":已实现与主机的连接"));
break;
}
case QFtp::LoggedIn: {
setInsertTextColor(Qt::black);
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+tr(":已实现连接和用户登录"));
break;
}
case QFtp::Closing: {
setInsertTextColor(Qt::black);
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+tr(":连接正在关闭"));
break;
}
default:
break;
}
}
ftp命令启动
void MainWindow::ftpCommandStarted(int)
{
if(ftpClient->currentCommand() == QFtp::ConnectToHost)
{
setInsertTextColor(Qt::black);
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+tr(":正在连接到服务器..."));
}
if (ftpClient->currentCommand() == QFtp::Login)
{
setInsertTextColor(Qt::black);
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+tr(":正在登录..."));
}
if (ftpClient->currentCommand() == QFtp::Get)
{
setInsertTextColor(Qt::black);
QFileInfo fi(globalCurrentFile);
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+":"+fi.fileName()+tr(":正在下载..."));
}
else if (ftpClient->currentCommand() == QFtp::Close)
{
setInsertTextColor(Qt::black);
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+tr(":正在关闭连接..."));
}
}
添加文件或文件夹至TreeWidget
void MainWindow::addToList(const QUrlInfo &urlInfo)
{
QTreeWidgetItem *item = new QTreeWidgetItem;
item->setText(0, urlInfo.name());
item->setText(1, QString::number(urlInfo.size()/1024));//KB
item->setText(2, urlInfo.owner());
item->setText(3, urlInfo.group());
item->setText(4, urlInfo.lastModified().toString("yyyy-MM-dd "));
//获取文件信息并存储
tagUrlInfo.allFileNamesList<<urlInfo.name();
tagUrlInfo.allFilesSizeList<<QString::number(urlInfo.size()/1024);
tagUrlInfo.allFilesOwnerList<<urlInfo.owner();
tagUrlInfo.allFilesGroupList<<urlInfo.group();
tagUrlInfo.allFilesLastModifiedList<<urlInfo.lastModified().toString("yyyy-MM-dd ");
QPixmap pixmap(urlInfo.isDir() ? "./res/dir.png" : "./res/file.png");
item->setIcon(0, pixmap);
isDirectory[urlInfo.name()] = urlInfo.isDir();
//存储该路径是否为目录的信息
ui->fileTreeWidget->setHeaderLabels(QStringList()<<"文件"<<"文件大小(KB)"<<"所有者"<<"所属组"<<"修改日期");
ui->fileTreeWidget->addTopLevelItem(item);
if (!ui->fileTreeWidget->currentItem())
{
ui->fileTreeWidget->setCurrentItem(ui->fileTreeWidget->topLevelItem(0));
ui->fileTreeWidget->setEnabled(true);
}
}
ftp命令完成。
void MainWindow::ftpCommandFinished(int,bool error)
{
if(ftpClient->currentCommand() == QFtp::ConnectToHost)
{
if(error)
{
setInsertTextColor(Qt::red);
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+tr(":连接服务器出现错误:%1")
.arg(ftpClient->errorString()));
}
else
{
setInsertTextColor(Qt::black);
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+tr(":连接到服务器成功"));
}
}
if (ftpClient->currentCommand() == QFtp::Login)
{
if(error)
{
setInsertTextColor(Qt::red);
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+tr(":登录出现错误:%1")
.arg(ftpClient->errorString()));
}
else
{
setInsertTextColor(Qt::black);
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+tr(":登录成功"));
//保存至配置文件
rwiniFile=new RWINIFile();
rwiniFile->writeIni(filePath,"FTPServer","FTPServer",ui->FTPServerLineEdit->text());
rwiniFile->writeIni(filePath,"FTPServer","FTPAccount",ui->FTPIDLineEdit->text());
rwiniFile->writeIni(filePath,"FTPServer","FTPPort",QString::number(ui->ftpServerPortSpinBox->value()));
delete rwiniFile;
rwiniFile=NULL;
ftpClient->list();//发射listInfo()信号,显示文件列表
}
}
if(ftpClient->currentCommand() == QFtp::List)
{
if(isDirectory.isEmpty())
{
//如果目录为空,显示"empty"
ui->fileTreeWidget->addTopLevelItem(new QTreeWidgetItem(QStringList()<<tr("<empty>")));
ui->fileTreeWidget->setEnabled(false);
// QMessageBox::information(this,"信息提示!","该目录为空!");
}
}
if (ftpClient->currentCommand() == QFtp::Get)
{
QFileInfo fi(globalCurrentFile);
if(error)
{
setInsertTextColor(Qt::red);
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+":"+fi.fileName()+tr(":下载出现错误:%1")
.arg(ftpClient->errorString()));
}
else
{
setInsertTextColor(Qt::black);
//此处需要关闭文件
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+":"+fi.fileName()+tr(":已经完成下载"));
globalCurrentDownloadFile->close();
// globalCurrentDownloadFile->deleteLater();
//下面内容需要加锁
ftpT->mutex->lock();
fileCount++;
isFinished=true;
ftpT->mutex->unlock();
}
}
else if (ftpClient->currentCommand() == QFtp::Close)
{
setInsertTextColor(Qt::black);
ui->infoTextEdit->append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")+tr(":已经关闭连接"));
}
}
打开一个目录
void MainWindow::processItem(QTreeWidgetItem* item,int) //打开一个目录
{
QString name = item->text(0);
if (isDirectory.value(name)) { //如果这个文件是个目录,则打开
ui->fileTreeWidget->clear();
isDirectory.clear();
currentPath += '/';
currentPath += name;
ftpClient->cd(name);
ftpClient->list();
// ui->cdToParentButton->setEnabled(true);
}
}
总结:
由于ftp是异步的,如果需要实时监测当前下载文件,需要使用多线程。