QT 实现FTP客户端

一、简述

本文基于QT5.8使用QNetworkAccessManager类进行利用FTP协议的上传和下载操作,Qt4中使用的QFtp模块在QT5后被移除,如果有需要可以去GitHub上下载编译后使用(官方地址:https://github.com/qt/qtftp),使用QFtp和QUrlInfo可以实现获得服务器端的文件路径,结合TreeWidget实现目录预览。现在官方推荐使用的是QNetworkAccessManager类,在使用QNetworkAccessManager类之前,请先保证自己的QT版本为QT5.X

我使用的服务器端是在Linux下配置的FTP服务器,客户端的QT代码是在Windows上编译运行的,FTP的服务器配置可以在我的另一篇博客中查看(https://blog.csdn.net/Sakuya__/article/details/86597994)。

本文代码下载:

CSDN下载

GitHub下载

百度云下载地址    提取码:wnnn

 


二、界面展示

输入FTP服务器地址,用户名和密码,我的Linux服务器IP地址为192.168.43.129,用户名为sakuya,密码为abcd1234。

QT 实现FTP客户端_第1张图片

点击上传按钮选择文件上传

QT 实现FTP客户端_第2张图片

上传成功后

QT 实现FTP客户端_第3张图片

 


三、代码

一、为了使用关于网络的类,首先,在Pro文件中加入一行

QT      += network

二、头文件mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

public slots:
    bool initFTP();

    void replyFinished(QNetworkReply*);

    void loadProgress(qint64 bytesSent, qint64 bytesTotal);

    QString getFileName(QString m_filePath);

    void readContent();

    void replyError(QNetworkReply::NetworkError error);

private slots:
    void on_Btn_upload_clicked();

    void on_Btn_download_clicked();

private:
    Ui::MainWindow *ui;

    QNetworkAccessManager *accessManager;

    QString ftpPath;
    QString user;
    QString password;

    QFile *file;

    QNetworkReply *reply;
};

#endif // MAINWINDOW_H

三、mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 设置进度条
    ui->progressBar->setValue(0);
    ui->progressBar->setAlignment(Qt::AlignRight | Qt::AlignVCenter); // 对齐方式
    ui->progressBar->setFormat(QString::fromUtf8("当前无任务:%1%").arg(QString::number(0, 'f', 1)));
}

MainWindow::~MainWindow()
{
    delete ui;
}

// 初始化记录URL地址,用户名,密码,并检测URL地址的合法性
bool MainWindow::initFTP()
{
    // 判断有没有填写URL地址和用户名、密码
    if (ui->lineEdit_ftp->text().isEmpty()) {
        QMessageBox::critical(NULL, tr("Error"), "URL地址不能为空");
        return false;
    }
    else if (ui->lineEdit_user->text().isEmpty()) {
        QMessageBox::critical(NULL, tr("Error"), "user不能为空");
        return false;
    }
    else if (ui->lineEdit_user->text().isEmpty()) {
        QMessageBox::critical(NULL, tr("Error"), "密码不能为空");
        return false;
    }
    else {
        ftpPath = ui->lineEdit_ftp->text();
        user = ui->lineEdit_user->text();
        password = ui->lineEdit_password->text();
        // 检测URL地址是否合法
        QUrl url = QUrl(ftpPath);
        if (!url.isValid()) {
            QMessageBox::critical(NULL, tr("Error"), "URL地址不合法!");
            return false;
        }
        else if (url.scheme() != "ftp") {
            QMessageBox::critical(NULL, tr("Error"), "URL地址必须以ftp开头!");
            return false;
        }
        return true;
    }
}

// 删除指针,更新和关闭文件
void MainWindow::replyFinished(QNetworkReply*)
{
    if (reply->error() == QNetworkReply::NoError) {
            reply->deleteLater();
            file->flush();
            file->close();
        }
        else {
            QMessageBox::critical(NULL, tr("Error"), "错误!!!");
        }
}

// 更新进度条
void MainWindow::loadProgress(qint64 bytesSent, qint64 bytesTotal)
{
    ui->progressBar->setValue(0);
    qDebug() << "loaded" << bytesSent << "of" << bytesTotal;
    ui->progressBar->setMaximum(bytesTotal); //最大值
    ui->progressBar->setValue(bytesSent);  //当前值
    double currentProgress = (bytesSent - ui->progressBar->minimum()) * 100.0 / (bytesTotal - ui->progressBar->minimum());
    ui->progressBar->setFormat(QString::fromUtf8("当前进度为:%1%").arg(QString::number(currentProgress, 'f', 1)));
}

// 获得传入路径的文件名
QString MainWindow::getFileName(QString m_filePath)
{
    QString temp;
    QString fileName;
    int count = -1;
    fileName = m_filePath;
    for(int i = 0; temp != "/"; i++)
    {
        temp = fileName.right(1);
        fileName.chop(1);
        count++;
    }
    fileName = m_filePath.right(count);

    return fileName;
}

// 下载过程出错,进行报错处理(超时处理也是丢出超时信号,交由此槽函数进行处理)
void MainWindow::replyError(QNetworkReply::NetworkError error)
{
    auto metaEnum = QMetaEnum::fromType();
    // 枚举值转换为字符串
    auto errStr = metaEnum.valueToKey(error);
    QMessageBox::critical(NULL, tr("Error"), QString(errStr));

    file->deleteLater();
    file = Q_NULLPTR;

    reply->deleteLater();
}

// 下载时向本地文件中写入数据
void MainWindow::readContent()
{
    file->write(reply->readAll());
}

// 上传文件
void MainWindow::on_Btn_upload_clicked()
{
    if (initFTP()) {
        // 得到选择的文件的路径,保存在字符串链表中
        QStringList string_list;
        string_list = QFileDialog::getOpenFileNames(this, tr("选择文件"), "", tr("Files (*)"));
        if (!string_list.isEmpty()) {
            for (int i = 0; i < string_list.count(); i++) {
                QString filePath;
                filePath = string_list.at(i);
                file = new QFile(filePath);
                file->open(QIODevice::ReadOnly);
                QByteArray byte_file = file->readAll();

                QString fileName;
                fileName = getFileName(filePath);
                QString m_ftpPath;
                m_ftpPath = ftpPath + "/" + fileName;

                // 把选中的文件上传到服务器
                accessManager = new QNetworkAccessManager(this);
                accessManager->setNetworkAccessible(QNetworkAccessManager::Accessible);
                QUrl url(m_ftpPath);
                url.setPort(21);
                url.setUserName(user);
                url.setPassword(password);

                QNetworkRequest request(url);
                reply = accessManager->put(request, byte_file);

                connect(accessManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(replyFinished(QNetworkReply*)));
                connect(reply, SIGNAL(uploadProgress(qint64 ,qint64)), this, SLOT(loadProgress(qint64 ,qint64)));
                connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),SLOT(replyError(QNetworkReply::NetworkError)));
            }
        }
    }
}

// 下载文件
void MainWindow::on_Btn_download_clicked()
{
    if (initFTP()) {
        QString folderPath;
        folderPath = QFileDialog::getExistingDirectory(this, tr("选择文件"), "", QFileDialog::ShowDirsOnly);
        file = new QFile(folderPath + "/test.jpg");
        file->open(QIODevice::WriteOnly);

        // 从服务器上下载文件到选中文件夹
        QNetworkAccessManager *accessManager = new QNetworkAccessManager(this);
        accessManager->setNetworkAccessible(QNetworkAccessManager::Accessible);
        QUrl url("ftp://192.168.43.129/software/timg.jpeg");
        url.setPort(21);
        url.setUserName("jinxiaodan");
        url.setPassword("abcd1234");

        QNetworkRequest request(url);
        reply = accessManager->get(request);

        connect((QObject *)reply, SIGNAL(readyRead()), this, SLOT(readContent()));
        connect(accessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
        connect(reply, SIGNAL(downloadProgress(qint64 ,qint64)), this, SLOT(loadProgress(qint64 ,qint64)));
        connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),SLOT(replyError(QNetworkReply::NetworkError)));
    }
}

以上则为全部代码,自己新建项目,把代码复制进去,按照开始展示的界面设置UI界面,把代码中的登录服务器地址、用户名和密码改为你自己的即可。

 


四、缺点

下载过程中文件写入是在主线程中进行的,如果文件过大,频繁写入会造成主线程卡顿现象。要避免此种情况,请在工作线程中进行。

另外,如果想要实现目录预览功能请使用QFtp和QUrlInfo,可以看到服务器端的文件目录,选择文件要下载的文件,QNetworkAccessManager只能更改源代码选择自己想要下载的文件。

 

你可能感兴趣的:(QT,QT,FTP客户端)