Qt之FTP实现--QFtp篇
前言
前文已经介绍了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篇相关推荐
- Qt之天气预报——界面优化篇(含源码+注释)
一.界面优化效果 下方为界面优化完成和优化前的效果对比. 优化前: 优化后: 二.优化内容 添加标题栏 添加图片(图图标素材源自阿里巴巴矢量图标库) 更新UI内容(微调大小.布局比例) 添加鼠标事件函 ...
- QT 实现FTP客户端
一.简述 本文基于QT5.8使用QNetworkAccessManager类进行利用FTP协议的上传和下载操作,Qt4中使用的QFtp模块在QT5后被移除,如果有需要可以去GitHub上下载编译后使用 ...
- QT 防止FTP 上传软件在断连处 Crash
前段时间发现项目中的上传FTP软件有可能会在从服务器申请断连时Crash, 所以加了一个Timer. 由于项目代码行数过大, 此处上传部分代码片段. timeoutTimer = new QTimer ...
- qt:tcp通信工具(Client篇)
1.说明 使用qt写一个类似网上常见的网络调试工具.此篇为Client端.下一遍再写Server端. 2.基本流程 Client端相对简单:创建QTcpSocket对象,为对象的readyRead,e ...
- QT界面开发--基础学习篇一(上)
一.Qt简单介绍: 1.QT的简单理解: Qt简单的说就是一种可以跨平台的编程语言工具,可以直接类比C语言和C++. 且一般QT的代码逻辑也是以C语言和C++(也可以适用于像JS的语言),可以直观理解 ...
- Qt之FTP上传/下载文件操作
一个简单的Ftp客户端文件上传/下载操作示例. 上传文件 QNetworkAccessManager manager; QUrl url; /* 设置通讯协议 */ url.setScheme(&qu ...
- python 读取鼠标选中文本_木辛老师的编程课堂:Python和Qt之页面布局实战篇(一)...
通过前几节课的学习,我们已经基本上掌握了使用Qt Designer完成简单的布局管理.通过这些知识的学习,我们算是对PyQt进行了初步的了解,也算是入门了! 但是仅仅掌握这些知识还是远远不够的: 高深 ...
- Qt工作笔记-如何打包我们用 Qt 写的软件 - Linux 篇
个人补充下,这里打包的机器和部署都一个内核,最好是一个厂家的. 原文地址: https://zhuanlan.zhihu.com/p/49919048 概述 这部分内容其实官方文档已经有介绍,包括三部 ...
- Qt之JSON教程-实战篇
以实战例子讲述JSON三兄弟的后续故事. 实战一:发送JSON网络请求 作为JSON老大哥的QJsonValue自知对面的大户人家妹子貌美如花,心里已经打起算盘,先下手为强,后下手遭殃.决定显示下 ...
最新文章
- 2017年全球AI芯片公司大盘点
- java runtime.exec 阻塞_关于Runtime.getRuntime().exec()产生阻塞的2个陷阱
- 2021-05-21 深入理解SLAM技术 【4】射影几何--2面中心射影
- python编程标准_Python常见编程规范总结
- python装饰器 property_python装饰器--@property
- linux下手动删除数据库实例
- html 手机复制到剪贴板,移动端和pc端的复制到剪贴板功能
- linux mem设备是什么,linux下/dev/mem分析
- 用Python一键批量将任意结构的CSV文件导入 SQLite_用 Python 使用 Google Colab?岂止是炫酷...
- 利用sklearn实现adaboost,以单一分类树为例
- 请教大家, 关于 $0118 号消息
- Windows XP 系统服务项优化
- LDA中文文本挖掘代码分享
- 谁手握账本?趣讲 ZK 的内存模型
- 微信小程序 上传图片失败
- Express 路由
- 苹果退款_苹果如何退款
- 【超分辨率】Zoom to Learn, Learn to Zoom
- duilib 关于wke 控件焦点问题
- JSch执行shell命令