閱讀406 返回首頁    go 阿裏雲 go 技術社區[雲棲]


[Qt教程] 第34篇 網絡(四)FTP(二)

[Qt教程] 第34篇 網絡(四)FTP(二)

樓主
 發表於 2013-9-4 15:04:38 | 查看: 315| 回複: 9
FTP(二)

版權聲明

該文章原創於作者yafeilinux,轉載請注明出處!


導語

前麵講述了一個最簡單的FTP客戶端程序的編寫,這一節我們將這個程序進行擴展,使其可以瀏覽並能下載服務器上的所有文件。



環境:Windows Xp + Qt 4.8.5+QtCreator 2.8.0



目錄


一、修改界麵
二、功能實現




正文


一、修改界麵


我們刪除了TextBrowser ,加入了幾個Label Line Edit Push Button部件,一個Tree Widget及一個Progress Bar部件。然後我們對其中幾個部件做如下更改。
1)將“FTP服務器”標簽後的Line EditobjectName屬性改為“ftpServerLineEdit”,其text 屬性改為“ftp.qt-project.org”。
2)將“用戶名”標簽後的Line EditobjectName屬性改為“userNameLineEdit”,其text屬性改為“anonymous”,將其toolTip屬性改為“默認用戶名請使用:anonymous ,此時密碼任意。”
3)將“密碼”標簽後的Line EditobjectName屬性改為“passWordLineEdit”,其text屬性改為“123456”,將其echoMode屬性改為“Password”。
4)將“連接”按鈕的objectName屬性改為“connectButton”。
5)將“返回上一級目錄”按鈕的objectName屬性改為“cdToParentButton”。
6)將“下載”按鈕的objectName屬性改為“downloadButton”。
7)將Tree WidgetobjectName屬性改為“fileList”,然後在Tree Widget部件上單擊鼠標右鍵,選擇Edit Items菜單,添加列屬性如下。

01.jpg


最終界麵如圖所示:


02.jpg



下麵我們的程序中,就是實現在用戶填寫完相關信息後,按下“連接”按鈕,就可以連接到FTP服務器,並在TreeWidget中顯示服務器上的所有文件,我們可以按下“下載”按鈕來下載選中的文件,並使用進度條顯示下載進度。


二、功能實現


1.更改widget.h文件。

1)添加頭文件#include <QtGui>

2)在private中添加變量:
QHash<QString, bool> isDirectory; //用來存儲一個路徑是否為目錄的信息
QString currentPath; //用來存儲現在的路徑
QFile *file;

3)添加槽:
private slots:
void on_downloadButton_clicked();
void on_cdToParentButton_clicked();
void on_connectButton_clicked();
void ftpCommandFinished(int,bool);
void ftpCommandStarted(int);
void updateDataTransferProgress(qint64,qint64 );//更新進度條
//將服務器上的文件添加到Tree Widget
void addToList(const QUrlInfo &urlInfo);
void processItem(QTreeWidgetItem*,int);//雙擊一個目錄時顯示其內容


2.更改widget.cpp的內容。

1)實現“連接”按鈕的單擊事件槽。
void Widget::on_connectButton_clicked()   //連接按鈕
{
    ui->fileList->clear();
    currentPath.clear();
    isDirectory.clear();
   
    ftp = new QFtp(this);
    connect(ftp,SIGNAL(commandStarted(int)),
this,SLOT(ftpCommandStarted(int)));
    connect(ftp,SIGNAL(commandFinished(int,bool)),
           this,SLOT(ftpCommandFinished(int,bool)));
    connect(ftp,SIGNAL(listInfo(QUrlInfo)),
this,SLOT(addToList(QUrlInfo)));
    connect(ftp,SIGNAL(dataTransferProgress(qint64,qint64)),
           this,SLOT(updateDataTransferProgress(qint64,qint64)));
   
    QString ftpServer = ui->ftpServerLineEdit->text();
    QString userName = ui->userNameLineEdit->text();
    QString passWord = ui->passWordLineEdit->text();
    ftp->connectToHost(ftpServer,21); //連接到服務器,默認端口號是21
    ftp->login(userName,passWord);   //登錄
}
我們在“連接”按鈕的單擊事件槽函數中新建了ftp對象,然後關聯了相關的信號和槽。這裏的listInfo()信號由ftp->list()函數發射,它將在登錄命令完成時調用,下麵我們提到。而dataTransferProgress()信號在數據傳輸時自動發射。最後我們從界麵上獲得服務器地址,用戶名和密碼等信息,並以它們為參數執行連接和登錄命令。


2)更改ftpCommandFinished()函數。
我們在相應位置做更改。

首先,在登錄命令完成時,我們調用list()函數:

ui->label->setText(tr("登錄成功"));
ftp->list();   //發射listInfo()信號,顯示文件列表   
然後,在下載命令完成時,我們使下載按鈕可用,並關閉打開的文件。
ui->label->setText(tr("已經完成下載"));
ui->downloadButton->setEnabled(true);
file->close();     
delete file;

最後再添加一個if語句,處理list命令完成時的情況:
if (ftp->currentCommand() == QFtp::List){
       if (isDirectory.isEmpty())
       { //如果目錄為空,顯示“empty”
           ui->fileList->addTopLevelItem(
                  new QTreeWidgetItem(QStringList()<< tr("<empty>")));
           ui->fileList->setEnabled(false);
           ui->label->setText(tr("該目錄為空"));
       }
}
我們在list命令完成時,判斷文件列表是否為空,如果為空,就讓Tree Widget不可用,並顯示“empty”條目。


3)添加文件列表函數的內容如下。
void Widget::addToList(const QUrlInfo &urlInfo)  //添加文件列表
{
    QTreeWidgetItem *item = new QTreeWidgetItem;
    item->setText(0, urlInfo.name());
    item->setText(1, QString::number(urlInfo.size()));
    item->setText(2, urlInfo.owner());
    item->setText(3, urlInfo.group());
    item->setText(4, urlInfo.lastModified().toString("MMM dd yyyy"));
   
    QPixmap pixmap(urlInfo.isDir() ? "../myFtp2/dir.png" : "../myFtp2/file.png");
    item->setIcon(0, pixmap);
   
    isDirectory[urlInfo.name()] = urlInfo.isDir();
    //存儲該路徑是否為目錄的信息
    ui->fileList->addTopLevelItem(item);
    if (!ui->fileList->currentItem()) {
       ui->fileList->setCurrentItem(ui->fileList->topLevelItem(0));
       ui->fileList->setEnabled(true);
    }
}
ftp->list()函數執行時會發射listInfo()信號,此時就會執行addToList()函數,在這裏我們將文件信息顯示在Tree Widget上,並在isDirectory中存儲該文件的路徑及其是否為目錄的信息。為了使文件與目錄進行區分,我們使用了不同的圖標file.pngdir.png來表示它們,這兩個圖標放在了工程文件夾中。


4)將構造函數的內容更改如下。
{
    ui->setupUi(this);
    ui->progressBar->setValue(0);
    //鼠標雙擊列表中的目錄時,我們進入該目錄
    connect(ui->fileList,SIGNAL(itemActivated(QTreeWidgetItem*,int)),
           this,SLOT(processItem(QTreeWidgetItem*,int)));
}
這裏我們隻是讓進度條的值為0,然後關聯了Tree Widget的一個信號itemActivated()。當鼠標雙擊一個條目時,發射該信號,我們在槽函數中判斷該條目是否為目錄,如果是則進入該目錄。


5processItem()函數的實現如下。
void Widget::processItem(QTreeWidgetItem* item,int)  //打開一個目錄
{
    QString name = item->text(0);
    if (isDirectory.value(name)) {  //如果這個文件是個目錄,則打開
       ui->fileList->clear();
       isDirectory.clear();
       currentPath += '/';
       currentPath += name;
       ftp->cd(name);
       ftp->list();
       ui->cdToParentButton->setEnabled(true);
    }
}

6)“返回上一級目錄”按鈕的單擊事件槽函數如下。
void Widget::on_cdToParentButton_clicked()  //返回上級目錄按鈕
{
    ui->fileList->clear();
    isDirectory.clear();
    currentPath = currentPath.left(currentPath.lastIndexOf('/'));
    if (currentPath.isEmpty()) {
       ui->cdToParentButton->setEnabled(false);
       ftp->cd("/");
    } else {
       ftp->cd(currentPath);
    }
    ftp->list();
}
在返回上一級目錄時,我們取當前路徑的最後一個“/”之前的部分,如果此時路徑為空了,我們就讓“返回上一級目錄”按鈕不可用。


7)“下載”按鈕單擊事件槽函數如下。
void Widget::on_downloadButton_clicked()  //下載按鈕
{
    QString fileName = ui->fileList->currentItem()->text(0);
    file = new QFile(fileName);
    if (!file->open(QIODevice::WriteOnly))
    {
       delete file;
       return;
}
//下載按鈕不可用,等下載完成後才可用
    ui->downloadButton->setEnabled(false);    ftp->get(ui->fileList->currentItem()->text(0), file);
}
在這裏我們獲取了當前項目的文件名,然後新建文件,使用get()命令下載服務器上的文件到我們新建的文件中。


8)更新進度條函數內容如下。
void Widget::updateDataTransferProgress( //進度條
                  qint64 readBytes,qint64 totalBytes)
{
    ui->progressBar->setMaximum(totalBytes);
    ui->progressBar->setValue(readBytes);
}


3.流程說明。
整個程序的流程就和我們實現函數的順序一樣。用戶在界麵上輸入服務器的相關信息,然後我們利用這些信息進行連接並登錄服務器,等登錄服務器成功時,我們列出服務器上所有的文件。對於一個目錄,我們可以進入其中,並返回上一級目錄,我們可以下載文件,並顯示下載的進度。
    對於ftp的操作,全部由那些命令和信號來完成,我們隻需要調用相應的命令,並在其發出信號時,進行對應的處理就可以了。而對於文件的顯示,則是視圖部分的知識了。


4.運行程序,效果如下圖所示。

03.jpg


04.jpg 




結語


最後需要說明的是,因為為了更好的講解知識,使得程序簡單化,所以我們省去了很多細節上的處理,如果需要,你可以自己添加。比如斷開連接和取消下載,你都可以使用
ftp->abort()函數。你也可以參考Qt自帶的Ftp Example例子。對於其他操作,比如上傳等,你可以根據需要添加。
      FTP的相關編程就講到到這裏。






涉及到的源碼下載:  myFtp2.rar (10.42 KB, 下載次數: 11) 

最後更新:2017-04-03 14:54:15

  上一篇:go [Qt教程] 第43篇 進階(三)對象樹與擁有權
  下一篇:go [Qt教程] 第15篇 2D繪圖(五)繪製圖片