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源码,直接下载后放到自己项目中就可以使用了。

下载地址


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部