QFtp的使用分享,附带源码,踩过的坑你就别踩了。

概要

源于嵌入式项目需要通过FTP上传/下载服务器的文件,使用QFtp实现,下附一个单例模式的共享库例子,有需要的伙伴可以留意一下,修修改改就能用。

创作不易,转载请注明作者,谢谢。

第一步,学习QFtp的使用函数

查阅qftp.h头文件,常用的函数都在此文件中可以看到,如下代码块所示:

    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);
上述的API接口简洁明了,此处不再赘述接口功能。

第二步,废话少说,直接上代码

.pro文件
QT       += core network
QT       -= gui
TARGET = FtpManager
TEMPLATE = lib
DEFINES += FTP_LIBRARY
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
        FtpManager.cpp\
    qftp.cpp \
    qurlinfo.cpp
HEADERS += \
        FtpManager.h \
        ftp_global.h \
    qftp.h \
    qurlinfo.h
unix {
    target.path = /usr/lib
    INSTALLS += target
}
CONFIG += plugin
CONFIG += debug_and_release
CONFIG(debug,debug|release){
    BuildType = debug
}else{
    BuildType = release
}
unix: DESTDIR = $$PWD/../../Bin
win32: DESTDIR = $$PWD/../../Bin/$$BuildType
FtpManager.h文件
#ifndef FTPMANAGER_H
#define FTPMANAGER_H

#include "ftp_global.h"
#include <QObject>
#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include "qftp.h"
#include "qurlinfo.h"

struct sFtpData;
class FTPSHARED_EXPORT cFtpManager : public QObject
{
    Q_OBJECT
public:
    explicit cFtpManager(QObject *parent = nullptr);
    ~cFtpManager();

private:
    void downloadFile(const QString &fileName);

private:
    sFtpData *d;
    static cFtpManager *mFtpManager;

public:
    static cFtpManager *getInstance();
    void connectFtp();
    void disconnectFtp();
    void uploadFile(const QString &fileName);
    void renameFile(const QString &oldName, const QString &newName);
    void deleteFile(const QString &fileName);
    bool isConnected() const;
    QFtp::State ftpState() const;

signals:
    void sigUpdateDataTransferProgress(qint64,qint64);
    void sigUploaded(bool);
    void sigDelete(bool);
    void sigRename(bool);

private slots:
    void ftpCommandFinished(int cmdId, bool error);
    void ftpStateChanged(int state);
    void addToList(const QUrlInfo &urlInfo);
    void updateDataTransferProgress(qint64 readBytes, qint64 totalBytes);
};

#endif // FTPMANAGER_H
FtpManager.cpp文件
#include "FtpManager.h"
#include <QFile>
#include <QDir>
#include <QDebug>
#include <QMutex>
#include <QDirIterator>
#include <QTimer>
#include <QTime>

#define Ftp_Ip  QString("192.168.11.88")
#define Ftp_Port 21
#define Ftp_Username QString("Administrator")
#define Ftp_Password QString("1")

struct sFtpData
{
    QFile *downloadFile = nullptr;
    QFile *uploadFile = nullptr;
    QFtp *ftp = nullptr;
    QTimer *timer = nullptr;
    QFtp::State mState;
};

cFtpManager *cFtpManager::mFtpManager = nullptr;

cFtpManager::cFtpManager(QObject *parent) : QObject(parent)
{
    d = new sFtpData;
    d->timer = new QTimer(this);
    connect(d->timer,&QTimer::timeout,this,[=]()
    {
        if(!d->ftp)
            return;
        if(isConnected()))
            downloadFile("timer.txt");	// 间隔20s下载一次文件,保持长连接
    });
    d->timer->start(20000);
}

cFtpManager::~cFtpManager()
{
    disconnectFtp();
    delete d;
}

cFtpManager *cFtpManager::getInstance()
{
    if(mFtpManager == nullptr)
    {
        static QMutex mutex;
        mutex.lock();
        mFtpManager = new cFtpManager;
        mutex.unlock();
    }

    return mFtpManager;
}

void cFtpManager::uploadFile(const QString &fileName)
{
    if(fileName.isEmpty())
        return;
    if(!isConnected())
    {
        emit sigUploaded(false);
        return;
    }
    QString localPath = QCoreApplication::applicationDirPath() + fileName;
    d->uploadFile = new QFile(localPath );
    if(d->uploadFile->open(QIODevice::ReadOnly | QIODevice::Text))
    {
        d->ftp->put(d->uploadFile,fileName);
    }
}

void cFtpManager::renameFile(const QString &oldName, const QString &newName)
{
    if(oldName.isEmpty() || newName.isEmpty())
        return;
    if(isConnected())
        d->ftp->rename(oldName,newName);
    else
        emit sigRename(false);
}

void cFtpManager::deleteFile(const QString &fileName)
{
    if(fileName.isEmpty())
        return;
    if(isConnected())
        d->ftp->remove(fileName);
    else
        emit sigDelete(false);
}

bool cFtpManager::isConnected() const
{
    if(ftpState() == QFtp::Connected || ftpState() == QFtp::LoggedIn)
        return true;
    else
        return false;
}

QFtp::State cFtpManager::ftpState() const
{
    return d->mState;
}

void cFtpManager::ftpCommandFinished(int cmdId, bool error)
{
    if(!d->ftp)
        return;

    switch (d->ftp->currentCommand()) {
    case QFtp::ConnectToHost:
    {
        if(error)
            disconnectFtp();          

    }break;
    case QFtp::Login:
    {
        if(error)
            return;
    }break;
    case QFtp::Cd:
    {
        if(error)
            return;
    }break;
    case QFtp::List:
    {
        if(error)
            return;
    }break;
    case QFtp::Get:
    {
        if(d->downloadFile && d->downloadFile->isOpen())
        {
            d->downloadFile->close();
            delete d->downloadFile;
        }
    }break;
    case QFtp::Put:
    {
        if(error)
            emit sigUploaded(false);
        else
            emit sigUploaded(true);
        if(d->uploadFile && d->uploadFile->isOpen())
        {
            d->uploadFile->close();
            delete d->uploadFile;
        }
    }break;
    case QFtp::Rename:
    {
        if(error)
            emit sigRename(true);
        else
            emit sigRename(false);

    }break;
    case QFtp::Remove:
    {
        if(error)
            emit sigDelete(true);
        else
            emit sigDelete(false);
    }break;
    default:
        break;
    }
}

void cFtpManager::ftpStateChanged(int state)
{
    if(!d->ftp)
        return;
    d->mState = d->ftp->state();
    switch (d->ftp->state()) {
    case QFtp::Connecting:
    {
        qDebug() << "ftp connecting";
    }break;
    case QFtp::Connected:
    {
        qDebug() << "ftp connected";
    }break;
    case QFtp::Unconnected:
    {
        qDebug() << "ftp Unconnected";
    }break;
    default:
        break;
    }
}

void cFtpManager::addToList(const QUrlInfo &urlInfo)
{
    if(urlInfo.isFile())
    {
        // 文件名称通过urlInfo.name()获取;
    }
}

void cFtpManager::updateDataTransferProgress(qint64 readBytes, qint64 totalBytes)
{
    emit sigUpdateDataTransferProgress(readBytes,totalBytes);
}

void cFtpManager::connectFtp()
{
    if(!d->ftp)
    {
        d->ftp = new QFtp(this);
        QObject::connect(d->ftp, SIGNAL(commandFinished(int,bool)),this, SLOT(ftpCommandFinished(int,bool)));
        QObject::connect(d->ftp, SIGNAL(stateChanged(int)),this, SLOT(ftpStateChanged(int)));
        QObject::connect(d->ftp, SIGNAL(listInfo(QUrlInfo)),this, SLOT(addToList(QUrlInfo)));
        QObject::connect(d->ftp, SIGNAL(dataTransferProgress(qint64,qint64)),this, SLOT(updateDataTransferProgress(qint64,qint64)));
    }
    d->ftp->connectToHost(Ftp_Ip,Ftp_Port);
    d->ftp->login(Ftp_Username,Ftp_Password);
}

void cFtpManager::disconnectFtp()
{
    if(d->ftp)
    {
        d->ftp->state();
        d->ftp->abort();
        d->ftp->deleteLater();
        d->ftp = nullptr;
        return;
    }
}

void cFtpManager::downloadFile(const QString &fileName)
{
    QString localPath = QCoreApplication::applicationDirPath() + fileName;
    d->downloadFile = new QFile(localPath );
    if(d->downloadFile->open(QIODevice::WriteOnly | QIODevice::Text))
    {
        d->ftp->get(fileName,d->downloadFile);
    }
}

关键注意事项!!!

1、保持与FTP服务器的长连接,需要进行一次FTP操作,我这里使用定时器隔20S获取一次timer.txt文件,文件内容为空。

2、QFtp重连的方式,必须先进行disconnect,调用abort()和deletelater(),然后将指针赋值为nullptr。

3、在断开QFtp连接之后,若剩余的操作未结束,返回ftpCommandFinished或ftpStateChanged,注意!!!此时QFtp指针已经被delete,需要对Qftp对象进行判空处理,若为nullptr则return,否则访问空指针导致崩溃。

4、QFtp的文件操作,是异步处理,若需要断开连接,请在创建QFtp的线程进行断开。

5、ftpCommandFinished和ftpStateChanged槽函数触发时,不要使用槽函数的形参,应使用QFtp对象的函数command()和state()来获取当前命令与当前状态。

小结

针对QFtp的操作,就到这里,大部分的FTP操作QFtp都是可以满足的,不过目前Qt官方已经废弃QFtp,使用QNetworkAccessManager来实现。以上例子仅用作分享,有建议可以留言交流,大家一起学习。

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值