使用Qt实现FTP客户端

本文介绍了一个基于QT网络库的FTP客户端实现,包括上传和下载功能,使用智能指针管理资源,通过QNetworkAccessManager进行网络操作,支持进度显示和错误处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

头文件ftp.h

#pragma once
#ifdef CREATEDELL_API_DU
#else
#define  CREATEDELL_API_DU  _declspec(dllexport)
#endif

#ifndef FTPCLIENT_H

#include <QtCore\QString>
#include <QtNetwork\QNetworkAccessManager>
#include <QtNetwork\QNetworkRequest>
#include <QtNetwork\QNetworkReply>
#include <QtCore\QUrl>
#include <QtCore\QFile>
#include <QtCore\QDir>
#include <QtCore\QDebug>
#include <QtCore\QObject>

#include <memory>




class CREATEDELL_API_DU FtpClient : public QObject
{
    Q_OBJECT

public:
    explicit FtpClient(QObject *parent = 0);
    virtual ~FtpClient();
    void setUrl();
    void setDir(const QString& dirpath);
    void setFile(QString& filename);
    void setPort(int port = 21);
    void setPath(QString& path);
    void setHost(QString& ip);
    void setPassword(QString& password);
    void setUserName(QString& username);
    void setPercent(qint64 bytesSent, qint64 bytesTotal);
    QNetworkReply::NetworkError getErrorCode();
    void FtpClient::setErrorCode(QNetworkReply::NetworkError errors);
public slots:
    void upload();
    void download(int& errCode);
    void readContent();
    void replyFinished(QNetworkReply*);
    void loadError(QNetworkReply::NetworkError);
    void loadProgress(qint64 bytesSent, qint64 bytesTotal);
    
public:
    virtual void onFinish() {}
    virtual qint64 getPersent() 
    { 
        return percent_; 
    }


private:
    QNetworkReply *reply_;
    std::shared_ptr<QFile> file_;
    std::shared_ptr<QUrl> url_;
    std::shared_ptr<QDir> dir_;
    std::shared_ptr<QNetworkAccessManager> accessManager_;
    qint64 percent_;
    QNetworkReply::NetworkError error_;
};

#endif // FTPCLIENT_H

 源文件ftp.cpp

#define CREATEDELL_API_DU _declspec(dllexport)

#include "ftp.h"

#include <iostream>
#include <QEventLoop>

CREATEDELL_API_DU FtpClient::FtpClient(QObject *parent) :
    QObject(parent), percent_(0)

{
    url_ = std::make_shared<QUrl>();
    url_->setScheme("ftp");
}


CREATEDELL_API_DU FtpClient::~FtpClient()
{

}


QNetworkReply::NetworkError FtpClient::getErrorCode()
{
    return this->error_;
}

void FtpClient::setErrorCode(QNetworkReply::NetworkError errors)
{
    this->error_ = errors;
}


void CREATEDELL_API_DU FtpClient::setDir(const QString& dirPath)
{
    dir_ = std::make_shared<QDir>(dirPath);
    if (!dir_->exists())
    {
        auto ok = dir_->mkdir(dirPath);
        if (!ok)
        {
            qDebug() << "make dir " << dirPath << " failed..." << endl;
        }
    }
}
void CREATEDELL_API_DU FtpClient::setUrl()
{
    url_ = std::make_shared<QUrl>();
    url_->setScheme("ftp");
}

void CREATEDELL_API_DU FtpClient::setFile(QString& fileName)
{
    file_ = std::make_shared<QFile>(dir_->absolutePath() + "/" + fileName);
}


void CREATEDELL_API_DU FtpClient::setPort(int port)
{
    if (nullptr != url_)
    {
        url_->setPort(port);
    }
}


void CREATEDELL_API_DU  FtpClient::setPercent(qint64 sendBytes, qint64 totalBytes)
{
    double result = 100.0 * sendBytes / totalBytes;
    this->percent_ = (int)result;
}


void CREATEDELL_API_DU FtpClient::setPassword(QString& password)
{
    if (nullptr != url_)
    {
        url_->setPassword(password);
    }
}


void CREATEDELL_API_DU FtpClient::setUserName(QString& userName)
{
    if (nullptr != url_)
    {
        url_->setUserName(userName);
    }
}


void CREATEDELL_API_DU FtpClient::setPath(QString& path)
{
    url_->setPath(path);
}


void CREATEDELL_API_DU FtpClient::setHost(QString& ip)
{
    url_->setHost(ip);
}


void CREATEDELL_API_DU FtpClient::upload()
{

    qDebug() << "upload file " << *file_ << " begin..." << endl;
    if (!file_->open(QIODevice::ReadOnly))
    {
        qDebug() << "open file " << *file_ << " failed..." << endl;
    }
    //创建一个QNetworkAccessManager实例,将accessManager指向它
    accessManager_ = std::make_shared<QNetworkAccessManager>(this);
    accessManager_->setNetworkAccessible(QNetworkAccessManager::Accessible);

    QNetworkRequest request(*url_);
    reply_ = accessManager_->put(request, file_.get());
    
    connect(accessManager_.get(), SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)),Qt::DirectConnection);
    connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(loadError(QNetworkReply::NetworkError)),Qt::DirectConnection);
    connect(reply_, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(loadProgress(qint64, qint64)),Qt::DirectConnection);
}


void CREATEDELL_API_DU FtpClient::download(int& errCode)
{
    errCode = 0;
    qDebug() << "download file " << *file_ << " begin..." << endl;
    file_->open(QIODevice::WriteOnly);  

    accessManager_ = std::make_shared<QNetworkAccessManager>(this);
    accessManager_->setNetworkAccessible(QNetworkAccessManager::Accessible);
    
    QNetworkRequest request(*url_);
    reply_ = accessManager_->get(request);

    connect(reply_, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
            [=, &errCode](QNetworkReply::NetworkError code)
    {
        file_->close();
        switch ((int)code)
        {
        case QNetworkReply::ConnectionRefusedError:
            qDebug() << "ConnectionRefusedError";
            break;
        case QNetworkReply::HostNotFoundError:
            qDebug() << "HostNotFoundError";
            break;
        case QNetworkReply::TimeoutError:
            qDebug() << "TimeoutError";
            break;
        case QNetworkReply::AuthenticationRequiredError:
        {
            qDebug() << "AuthenticationRequiredError";
            errCode = code;
            break;
        }
        default:
        {
            errCode = code;
            break;
        }
        }
    });

    connect((QObject *)reply_, SIGNAL(readyRead()), this, SLOT(readContent()));
    connect((QObject*)(accessManager_.get()), SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)),Qt::DirectConnection);
    //connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(loadError(QNetworkReply::NetworkError)),Qt::DirectConnection);
    connect(reply_, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(loadProgress(qint64, qint64)),Qt::DirectConnection);

    QEventLoop eventloop;
    connect((QObject*)(accessManager_.get()), SIGNAL(finished(QNetworkReply*)), &eventloop, SLOT(quit()));
    eventloop.exec(QEventLoop::ExcludeUserInputEvents);
}


void CREATEDELL_API_DU FtpClient::readContent()
{
    file_->write(reply_->readAll());
}


void CREATEDELL_API_DU FtpClient::replyFinished(QNetworkReply* replys)
{
    if (reply_->error() == QNetworkReply::NoError)
    {
        qDebug() << "end..." << endl;
        reply_->deleteLater();
        file_->flush();
        file_->close();
		
		//发送传输完成信号
        onFinish();
    }
    else
    {
        //QMessageBox::critical(NULL, tr("Error"), "Failed!!!");
        qDebug() << "Error Failed!!!" << endl;
    }
}



void CREATEDELL_API_DU FtpClient::loadError(QNetworkReply::NetworkError)
{
    qDebug() << "Error: " << reply_->error();
    setErrorCode( reply_->error());
}


void CREATEDELL_API_DU FtpClient::loadProgress(qint64 bytesSend, qint64 bytesTotal)
{
    setPercent(bytesSend, bytesTotal);
    qDebug() << "loaded" << bytesSend << "of" << bytesTotal << "  " << getPersent() << "%";
}

<think>好的,用户想了解如何使用Qt实现FTP客户端的解决方案或示例代码。我需要结合之前提供的引用内容来回答。首先,用户的问题集中在QtFTP实现,可能需要区分不同版本的Qt,因为引用里提到QFtp模块在Qt5.15之后被QtNetwork取代。 首先,我应该检查用户提供的引用。引用[2]和[4]提到了QFtp模块,但引用[3]和[4]也提到了QNetworkAccessManager。所以需要说明不同Qt版本下使用不同的方法。用户可能需要知道两种方法:旧版的QFtp和新版的QtNetwork。 然后,我需要组织回答结构,分步骤说明两种实现方式。比如,对于Qt5.12及以下版本,使用QFtp模块,而5.15及以上使用QtNetwork。然后给出示例代码,可能的话,代码部分需要区分这两种情况。 用户需要示例代码,所以应该提供两种情况的代码片段。例如,使用QFtp的连接服务器和下载文件的方法,以及使用QNetworkAccessManager的上传和下载示例。同时,要确保代码语法正确,用中文注释,并解释关键步骤。 另外,用户可能关心环境配置和注意事项,比如如何安装QFtp模块,或者在新版本中如何处理。引用[2]提到需要Qt5.0及以上,而引用[4]指出QFtp在5.15后不再维护,所以需要注意这些细节。 还要考虑用户可能遇到的问题,比如跨平台的支持,代码的移植性,以及如何处理不同FTP服务器的设置。引用[2]中的注意事项部分可以在这里提及,比如调整连接参数或API变化。 最后,生成相关问题,帮助用户进一步了解优化方法、错误处理或替代方案。这些问题应该基于回答中的内容,比如性能优化、断点续传等。 总结回答结构:版本区分、两种实现方式的步骤、代码示例、注意事项、相关问题。确保引用正确,比如引用[2]和[3]、[4]来支持不同方法的说明。</think>根据Qt版本差异,FTP客户端实现可分为两种技术路线,以下分步骤说明具体实现方法: 一、Qt 5.15以下版本(使用QFtp模块) 1. 环境配置:在.pro文件中添加网络模块 ```qmake QT += network ``` 2. 基本连接示例(引用[2]实现) ```cpp #include <QFtp> QFtp *ftp = new QFtp(this); ftp->connectToHost("ftp.example.com", 21); ftp->login("username", "password"); // 目录操作 ftp->list(); // 获取目录列表 ftp->cd("/uploads"); // 切换目录 // 下载文件 ftp->get("file.txt", QFile("local.txt")); ``` 二、Qt 5.15及以上版本(使用QNetworkAccessManager) 1. 文件上传实现(引用[3][4]方法) ```cpp QUrl ftpUrl("ftp://10.10.10.108/upload/test.txt"); ftpUrl.setUserName("user"); ftpUrl.setPassword("pass123"); QFile *file = new QFile("local.txt"); file->open(QIODevice::ReadOnly); QNetworkReply *reply = manager->put(QNetworkRequest(ftpUrl), file); connect(reply, &QNetworkReply::finished, [=](){ qDebug() << "Upload finished"; }); ``` 2. 文件下载实现 ```cpp QNetworkReply *reply = manager->get(QNetworkRequest(QUrl("ftp://10.10.10.108/download/file.zip"))); connect(reply, &QNetworkReply::readyRead, [=](){ QFile output("file.zip"); output.write(reply->readAll()); }); ``` 三、注意事项 1. 协议支持差异:QFtp支持完整FTP命令集,而QNetworkAccessManager仅支持基础文件传输[^2][^4] 2. 安全连接:建议使用FTPS(FTP over SSL)替代明文传输 3. 跨平台特性:两种方案均支持Windows/Linux/macOS系统[^2][^3] 4. 进度监控:可通过信号机制实现 ```cpp // QFtp进度跟踪 connect(ftp, &QFtp::dataTransferProgress, [](qint64 done, qint64 total){ qDebug() << "Progress:" << done*100/total << "%"; }); ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值