1. 程式人生 > >Qt之FTP上傳/下載

Qt之FTP上傳/下載

文章轉載:http://blog.csdn.net/liang19890820/article/details/53188182


簡述

為了方便網路程式設計,Qt 提供了 Network 模組。該模組包含了許多類,例如:QFtp - 能夠更加輕鬆使用 FTP 協議進行網路程式設計。

但是,從 Qt5.x 之後,Qt Network 發生了很大的變化,助手中關於此部分描述如下:

The QFtp and QUrlInfo classes are no longer exported. Use QNetworkAccessManager instead. Programs that require raw FTP or HTTP streams can use the Qt FTP and Qt HTTP compatibility add-on modules that provide the QFtp and QHttp classes as they existed in Qt 4.

意思是說:不再匯出 QFtp 和 QUrlInfo 類,改用 QNetworkAccessManager。

開啟 FTP 服務

Linux 下實現 FTP 服務的軟體很多,最常見的有:vsftpd、Wu-ftpd 和 Proftp 等。

訪問 FTP 伺服器時需要經過驗證,只有經過了 FTP 伺服器的相關驗證,使用者才能訪問和傳輸檔案。

首先,伺服器需要安裝 FTP 軟體,以 vsftpd 為例:

[root@localhost wang]# which vsftpd
/sbin/vsftpd
  • 1
  • 2
  • 1
  • 2

這說明伺服器已經安裝了 vsftpd,再進行一系列配置即可使用。

關於 FTP 服務的搭建、配置屬於 linux 範疇,這裡就不過多贅述了,請自行檢視資料。

效果

實現效果如下:

這裡寫圖片描述

如果要獲取更多關於:檔案剩餘大小、平均速度、瞬時速度 、剩餘時間等相關資訊,請參考:Qt之HTTP上傳/下載

FtpManager

為了便於使用,封裝一個簡單的 FtpManager 管理類,用於上傳、下載檔案。

FTPManager.h

#ifndef FTP_MANAGER
#define FTP_MANAGER

#include <QUrl>
#include <QFile>
#include <QNetworkReply>
#include <QNetworkAccessManager>

class FtpManager : public QObject
{
    Q_OBJECT

public:
    explicit FtpManager(QObject *parent = 0);
    // 設定地址和埠
    void setHostPort(const QString &host, int port = 21);
    // 設定登入 FTP 伺服器的使用者名稱和密碼
    void setUserInfo(const QString &userName, const QString &password);
    // 上傳檔案
    void put(const QString &fileName, const QString &path);
    // 下載檔案
    void get(const QString &path, const QString &fileName);

signals:
    void error(QNetworkReply::NetworkError);
    // 上傳進度
    void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
    // 下載進度
    void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);

private slots:
    // 下載過程中寫檔案
    void finished();

private:
    QUrl m_pUrl;
    QFile m_file;
    QNetworkAccessManager m_manager;
};

#endif // FTP_MANAGER
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

FTPManager.cpp

#include <QFileInfo>
#include "FTPManager.h"

FtpManager::FtpManager(QObject *parent)
    : QObject(parent)
{
    // 設定協議
    m_pUrl.setScheme("ftp");
}

// 設定地址和埠
void FtpManager::setHostPort(const QString &host, int port)
{
    m_pUrl.setHost(host);
    m_pUrl.setPort(port);
}

// 設定登入 FTP 伺服器的使用者名稱和密碼
void FtpManager::setUserInfo(const QString &userName, const QString &password)
{
    m_pUrl.setUserName(userName);
    m_pUrl.setPassword(password);
}

// 上傳檔案
void FtpManager::put(const QString &fileName, const QString &path)
{
    QFile file(fileName);
    file.open(QIODevice::ReadOnly);
    QByteArray data = file.readAll();

    m_pUrl.setPath(path);
    QNetworkReply *pReply = m_manager.put(QNetworkRequest(m_pUrl), data);

    connect(pReply, SIGNAL(uploadProgress(qint64, qint64)), this, SIGNAL(uploadProgress(qint64, qint64)));
    connect(pReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SIGNAL(error(QNetworkReply::NetworkError)));
}

// 下載檔案
void FtpManager::get(const QString &path, const QString &fileName)
{
    QFileInfo info;
    info.setFile(fileName);

    m_file.setFileName(fileName);
    m_file.open(QIODevice::WriteOnly | QIODevice::Append);
    m_pUrl.setPath(path);

    QNetworkReply *pReply = m_manager.get(QNetworkRequest(m_pUrl));

    connect(pReply, SIGNAL(finished()), this, SLOT(finished()));
    connect(pReply, SIGNAL(downloadProgress(qint64, qint64)), this, SIGNAL(downloadProgress(qint64, qint64)));
    connect(pReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SIGNAL(error(QNetworkReply::NetworkError)));
}

// 下載過程中寫檔案
void FtpManager::finished()
{
    QNetworkReply *pReply = qobject_cast<QNetworkReply *>(sender());
    switch (pReply->error()) {
    case QNetworkReply::NoError : {
        m_file.write(pReply->readAll());
        m_file.flush();
    }
        break;
    default:
        break;
    }

    m_file.close();
    pReply->deleteLater();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

註釋很詳細,我就不再多做解釋了。。。

注意:下載過程中檔案寫入是在主執行緒中進行的,如果檔案過大,頻繁寫入會造成主執行緒卡頓現象。要避免此種情況,請在工作執行緒中進行。

使用

這裡,只貼主要程式碼:

// 構建需要的控制元件
QPushButton *pUploadButton = new QPushButton(this);
QPushButton *pDownloadButton = new QPushButton(this);
m_pUploadBar = new QProgressBar(this);
m_pDownloadBar = new QProgressBar(this);

pUploadButton->setText(QString::fromLocal8Bit("上傳"));
pDownloadButton->setText(QString::fromLocal8Bit("下載"));

// 接訊號槽
connect(pUploadButton, SIGNAL(clicked(bool)), this, SLOT(upload()));
connect(pDownloadButton, SIGNAL(clicked(bool)), this, SLOT(download()));

// 設定 FTP 相關資訊
m_ftp.setHostPort("192.168.***.***", 21);
m_ftp.setUserInfo("wang", "123456");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

其中,m_ftp 是類變數 FtpManager。

// 上傳檔案
void MainWindow::upload()
{
    m_ftp.put("E:\\Qt.zip", "/home/wang/Qt.zip");
    connect(&m_ftp, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError)));
    connect(&m_ftp, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgress(qint64, qint64)));
}

// 下載檔案
void MainWindow::download()
{
    m_ftp.get("/home/wang/Qt.zip", "F:\\Qt.zip");
    connect(&m_ftp, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError)));
    connect(&m_ftp, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgress(qint64, qint64)));
}

// 更新上傳進度
void MainWindow::uploadProgress(qint64 bytesSent, qint64 bytesTotal)
{
    m_pUploadBar->setMaximum(bytesTotal);
    m_pUploadBar->setValue(bytesSent);
}

// 更新下載進度
void MainWindow::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
    m_pDownloadBar->setMaximum(bytesTotal);
    m_pDownloadBar->setValue(bytesReceived);
}

// 錯誤處理
void MainWindow::error(QNetworkReply::NetworkError error)
{
    switch (error) {
    case QNetworkReply::HostNotFoundError :
        qDebug() << QString::fromLocal8Bit("主機沒有找到");
        break;
        // 其他錯誤處理
    default:
        break;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

在上傳、下載過程中,確保 Server 端的路徑存在:

[root@localhost wang]# pwd
/home/wang
[root@localhost wang]# ls
hello.sh
[root@localhost wang]#
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

上傳完成後,可以去 Server 端檢視一下:

[[email protected] wang]# ls -l
總用量 52980
-rw-r--r-- 1 root root       20 1116 14:01 hello.sh
-rw-r--r-- 1 wang  wang  54246299 1116 17:36 Qt.zip
[[email protected] wang]# md5sum Qt.zip 
8d010354447515d55c65d733bbba2682  Qt.zip
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

原始檔 Qt.zip 的大小為 54,246,299 位元組,顯然,目標檔案也一樣(可使用 MD5 比對,看檔案是否損壞),這說明已經完全上傳成功了。