前言

前文已经介绍了Qt项目中实现FTP上传文件的三种实现方式,今天主要看QFtp的实现,以及接口在使用过程中需要注意的问题避坑。

QFtp主要接口如下:

    int setProxy(const QString &host, quint16 port);int connectToHost(const QString &host, quint16 port=21);int login(const QString &user = QString(), const QString &password = QString());int close();int setTransferMode(TransferMode mode);int list(const QString &dir = QString());int cd(const QString &dir);int get(const QString &file, QIODevice *dev=0, TransferType type = Binary);int put(const QByteArray &data, const QString &file, TransferType type = Binary);int put(QIODevice *dev, const QString &file, TransferType type = Binary);int remove(const QString &file);int mkdir(const QString &dir);int rmdir(const QString &dir);int rename(const QString &oldname, const QString &newname);int rawCommand(const QString &command);

正文

首先我们要知道ftp服务器端的IP地址,以及端口号,前面我们介绍到FTP协议有两种方式,主动模式和被动模式(这里不做过多介绍,感兴趣的可以去查阅相关资料),通常开发都是使用被动模式,这种比较简单,由服务器端默认端口地址为21,客户端连接。

接着需要登录ftp的账号和密码,知道这几个数据后就可以连接服务器了。

我们看一下相关接口:

QFtp ftp;
ftp.connectToHost(ipAddr,21);  //端口默认是21
ftp.login(account,pwd);

很简单,先连接主机,然后登录,ok 搞定~

接下来看部分具体功能的实现。

文件上传

这两个接口负责文件上传:

int put(const QByteArray &data, const QString &file, TransferType type = Binary);
int put(QIODevice *dev, const QString &file, TransferType type = Binary);

1.第二个参数是指定文件在服务器端存储的完整文件路径,第三个参数指定上传方式,上一篇文章有降到可以通过文本模式(ASCII)和二进制模式上传,默认是使用二进制模式,如果使用文本模式的话,上传后的文件大小会发生变化变化,具体原因看前一篇博客介绍。所以通常都使用二进制模式。
2.第一个参数是传输文件内容,有两种方式,一是直接读取文件的所有内容,而是指定文件设备的指针

注意:有两种情况下不能使用第一个接口,读取所有文件内容进行上传

  • 1.如果上传的文件很大,几个G,这时候如果直接读取文件所有内容,会导致内存飙升;
  • 2.如果要展示上传进度,也不能使用第一个接口,否则 dataTransferProgress信号看不到实际的传输进度;

所以以上两种情况,必须使用第二个接口进行上传。

那么该如何调用这两个接口呢,简单说明下:
首先第一个:

int put(const QByteArray &data, const QString &file, TransferType type = Binary);
QFile file(a.txt);
if(file.open(QIODevice::ReadOnly)){ftp.put(file.readAll(),"a.txt");
}
...

很简单吧,第二个参数是指定文件在服务器端存储的完整文件路径,这里默认存储到服务器的根目录下,如果要放到子目录,可以在这个参数指定其完整路径,如: "/file/a.txt", 但前提是 "/file"目录在服务端已经存在,如果不存在,需要先创建好该目录,否则将会上传失败。关键目录的创建,后面会介绍。

第二个接口:

int put(QIODevice *dev, const QString &file, TransferType type = Binary);
QFile *file = new QFile(a.txt);
if(file->open(QIODevice::ReadOnly)){ftp.put(file,"a.txt");
}
...

更推荐使用第二种方式,不会占用太多内存空间,解决超大文件上传占内存导致程序卡死的问题,其次,可以实时通过信号dataTransferProgress知道其上传进度。

关于上传进度,我们可以绑定信号来获取:

connect(&ftp,&QFtp::dataTransferProgress,this,[=,&fileInfo,&ftp](qint64 readBytes,qint64 totalBytes){auto percent = (qreal)readBytes/totalBytes;//...if(percent == 1){if(file->isOpen()){file->close();}ftp.disconnect();ftp.close();}
});

当上传完成后,记得关闭文件,断开ftp连接。

获取文件列表、清空文件夹

这两个功能一起说明,假设有这样一个需求,需要上传文件到一个指定的文件夹中,上传之前检查该文件夹中是否有文件,如果有的话就将其删除,这个需求涵盖了获取文件列表、清空文件夹三个功能,接下来看一下如何实现:

    QEventLoop loop;QFtp ftp;QString path = "/xxxx/";ftp.connectToHost(ipAddr,port);ftp.login(account,pwd);QStringList names;int count = 0;connect(&ftp, &QFtp::listInfo, this, [&](QUrlInfo info){qDebug() << "listInfo=" << info.name();names.append(info.name());});connect(&ftp,&QFtp::commandFinished,this,[&](){if(ftp.currentCommand() == QFtp::List){qDebug() << "commandFinished List=" << ftp.errorString() << ftp.error();if(ftp.error() == 0){if(names.size() > 0){qDebug() << "----remove file----";foreach (auto &it, names) {ftp.remove(path + "/" + it);}}else{loop.quit();}}}else if(ftp.currentCommand() == QFtp::Remove){qDebug() << "currentCommand Remove." << ftp.errorString() << ftp.error();if(ftp.error() == 0){count++;//文件删除完后退出事件循环if(count == names.size()){loop.quit();}}}});ftp.list(path);  //获取文件列表loop.exec();ftp.close();

由于FTP操作是异步的,我这里为了达到同步效果,所以加了一个事件循环QEventLoop 。

新建文件夹

新建文件夹操作和上面类似,调用mkdir接口,如果文件夹已经存在,则会创建失败,会有报错信息,ftp.error()不等于0 :

    QEventLoop loop;QFtp ftp;QString path = "/xxxx/";ftp.connectToHost(ipAddr,port);ftp.login(account,pwd);connect(&ftp,&QFtp::commandFinished,this,[&](){if(ftp.currentCommand() == QFtp::Mkdir){qDebug() << "currentCommand Mkdir." << ftp.errorString() << ftp.error();loop.quit();}});ftp.mkdir(path);loop.exec();ftp.close();

以上,以上介绍了几个主要的接口,其它功能的实现也是类似的,直接查看接口参数就知道了。

QFtp文件

QFtp源码下载地址:https://github.com/qt/qtftp
网上很多教程,如何编译QFtp源码生成动态库。我个人亲身经验,编译很麻烦,就算编译完还要导入动态库,并且还要解决文件编码的问题,要不然无法识别中文路径,与其搞这么麻烦,干嘛不直接就源码呢,也就两个类,直接引用到项目中就可以了,这种方式最直接,修改源码也方便。

关于编码的问题,要修改一下源代码,参考这里

如果还嫌麻烦的话,我已经打包好改过的QFtp源码,直接下载后放到自己项目中就可以使用了。

下载地址

Qt之FTP实现--QFtp篇相关推荐

  1. Qt之天气预报——界面优化篇(含源码+注释)

    一.界面优化效果 下方为界面优化完成和优化前的效果对比. 优化前: 优化后: 二.优化内容 添加标题栏 添加图片(图图标素材源自阿里巴巴矢量图标库) 更新UI内容(微调大小.布局比例) 添加鼠标事件函 ...

  2. QT 实现FTP客户端

    一.简述 本文基于QT5.8使用QNetworkAccessManager类进行利用FTP协议的上传和下载操作,Qt4中使用的QFtp模块在QT5后被移除,如果有需要可以去GitHub上下载编译后使用 ...

  3. QT 防止FTP 上传软件在断连处 Crash

    前段时间发现项目中的上传FTP软件有可能会在从服务器申请断连时Crash, 所以加了一个Timer. 由于项目代码行数过大, 此处上传部分代码片段. timeoutTimer = new QTimer ...

  4. qt:tcp通信工具(Client篇)

    1.说明 使用qt写一个类似网上常见的网络调试工具.此篇为Client端.下一遍再写Server端. 2.基本流程 Client端相对简单:创建QTcpSocket对象,为对象的readyRead,e ...

  5. QT界面开发--基础学习篇一(上)

    一.Qt简单介绍: 1.QT的简单理解: Qt简单的说就是一种可以跨平台的编程语言工具,可以直接类比C语言和C++. 且一般QT的代码逻辑也是以C语言和C++(也可以适用于像JS的语言),可以直观理解 ...

  6. Qt之FTP上传/下载文件操作

    一个简单的Ftp客户端文件上传/下载操作示例. 上传文件 QNetworkAccessManager manager; QUrl url; /* 设置通讯协议 */ url.setScheme(&qu ...

  7. python 读取鼠标选中文本_木辛老师的编程课堂:Python和Qt之页面布局实战篇(一)...

    通过前几节课的学习,我们已经基本上掌握了使用Qt Designer完成简单的布局管理.通过这些知识的学习,我们算是对PyQt进行了初步的了解,也算是入门了! 但是仅仅掌握这些知识还是远远不够的: 高深 ...

  8. Qt工作笔记-如何打包我们用 Qt 写的软件 - Linux 篇

    个人补充下,这里打包的机器和部署都一个内核,最好是一个厂家的. 原文地址: https://zhuanlan.zhihu.com/p/49919048 概述 这部分内容其实官方文档已经有介绍,包括三部 ...

  9. Qt之JSON教程-实战篇

    以实战例子讲述JSON三兄弟的后续故事. 实战一:发送JSON网络请求   作为JSON老大哥的QJsonValue自知对面的大户人家妹子貌美如花,心里已经打起算盘,先下手为强,后下手遭殃.决定显示下 ...

最新文章

  1. 2017年全球AI芯片公司大盘点
  2. java runtime.exec 阻塞_关于Runtime.getRuntime().exec()产生阻塞的2个陷阱
  3. 2021-05-21 深入理解SLAM技术 【4】射影几何--2面中心射影
  4. python编程标准_Python常见编程规范总结
  5. python装饰器 property_python装饰器--@property
  6. linux下手动删除数据库实例
  7. html 手机复制到剪贴板,移动端和pc端的复制到剪贴板功能
  8. linux mem设备是什么,linux下/dev/mem分析
  9. 用Python一键批量将任意结构的CSV文件导入 SQLite_用 Python 使用 Google Colab?岂止是炫酷...
  10. 利用sklearn实现adaboost,以单一分类树为例
  11. 请教大家, 关于 $0118 号消息
  12. Windows XP 系统服务项优化
  13. LDA中文文本挖掘代码分享
  14. 谁手握账本?趣讲 ZK 的内存模型
  15. 微信小程序 上传图片失败
  16. Express 路由
  17. 苹果退款_苹果如何退款
  18. 【超分辨率】Zoom to Learn, Learn to Zoom
  19. duilib 关于wke 控件焦点问题
  20. JSch执行shell命令

热门文章

  1. WebRTC系列之音频的那些事
  2. Redux源码分析(一)
  3. Win10修改防火墙入站规则
  4. ubuntu首次给root用户设置密码和root用户登录设置
  5. Bower 使用指南
  6. Jenkins集成java非maven/ant项目的打包思路
  7. iOS五种本地缓存数据方式
  8. Linux手动添加用户、相关文件说明
  9. linux常用命令(2)常用系统工作命令
  10. win11 WSL centos7安装docker命令整理