<a target="_blank" href="http://bbs.qter.org/forum.php?mod=viewthread&tid=602">樓主</a>
發表于 2013-9-4 14:52:46 | 檢視:
392| 回複: 8
ftp(一)
版權聲明
該文章原創于作者yafeilinux,轉載請注明出處!
導語
上一節我們講述了http的程式設計,這一節講述與其及其相似的ftp的程式設計。ftp即filetransfer
protocol,也就是檔案傳輸協定。ftp的主要作用,就是讓使用者連接配接上一個遠端計算機,檢視遠端計算機有哪些檔案,然後把檔案從遠端計算機上拷貝到本地計算機,或者把本地計算機的檔案送到遠端計算機上。
環境:windows xp + qt 4.8.5+qtcreator 2.8.0
目錄
一、簡介
二、實作簡單的檔案下載下傳
正文
在qt中,我們可以使用上一節講述的qnetworkaccessmanager和qnetworkreply類來進行ftp 程式的編寫,因為它們用起來很簡單。但是,對于較複雜的ftp操作,qt還提供了qftp類,利用這個類,我們很容易寫出一個ftp用戶端程式。下面我們先在幫助中檢視這個類。
在qftp中,所有的操作都對應一個特定的函數,我們可以稱它們為指令。如connecttohost()連接配接到伺服器指令,login()登入指令,get()下載下傳指令,mkdir()建立目錄指令等。因為qftp類以異步方式工作,是以所有的這些函數都不是阻塞函數。也就是說,如果一個操作不能立即執行,那麼這個函數就會直接傳回,直到程式控制權傳回qt事件循環後才真正執行,它們不會影響界面的顯示。
所有的指令都傳回一個int 型的編号,使用這個編号讓我們可以跟蹤這個指令,檢視其執行狀态。當每條指令開始執行時,都會發出commandstarted()信号,當該指令執行結束時,會發出commandfinished()信号。我們可以利用這兩個信号和指令的編号來擷取指令的執行狀态。當然,如果不想執行每條指令都要記下它的編号,也可以使用currentcommand()來擷取現在執行的指令,其傳回值與指令的對應關系如下圖。
下面我們先看一個簡單的ftp用戶端的例子,然後對它進行擴充。在這個例子中我們從ftp伺服器上下載下傳一個檔案并顯示出來。
1.我們建立qt gui應用。
項目名次為“myftp”,基類選擇qwidget,類名保持widget即可。完成後打開muftp.pro檔案,在上面添加一行:qt +=
network,然後儲存該檔案。
2.修改widget.ui檔案。
在其中添加一個textbrowser 和一個 label,效果如下。
3.在main.cpp中進行修改。
為了在程式中可以使用中文,我們在main.cpp中添加頭檔案#include <qtextcodec>
并在main()函數中添加代碼:
qtextcodec::setcodecfortr(qtextcodec::codecforlocale());
4.在widget.h中進行修改。
先添加頭檔案:#include <qftp>
再在private中定義對象:qftp *ftp;
添加私有槽函數:
private slots:
void ftpcommandstarted(int);
void ftpcommandfinished(int,bool);
5.在widget.cpp中進行更改。
(1)在構造函數中添加代碼:
ftp = new qftp(this);
ftp->connecttohost("ftp.qt-project.org"); //連接配接到伺服器
ftp->login(); //登入
ftp->cd("qt/source"); //跳轉到“qt”目錄下的source目錄中
ftp->get("install"); //下載下傳“install”檔案
ftp->close(); //關閉連接配接
// 當每條指令開始執行時發出相應的信号
connect(ftp,signal(commandstarted(int)),
this,slot(ftpcommandstarted(int)));
// 當每條指令執行結束時發出相應的信号
connect(ftp,signal(commandfinished(int,bool)),
this,slot(ftpcommandfinished(int,bool)));
複制代碼
我們在構造函數裡執行了幾個ftp的操作,登入站點,并下載下傳了一個檔案。然後又關聯了兩個信号和槽,用來跟蹤指令的執行情況。
(2)實作槽函數:
void widget::ftpcommandstarted(int)
{
if(ftp->currentcommand() == qftp::connecttohost){
ui->label->settext(tr("正在連接配接到伺服器..."));
}
if (ftp->currentcommand() == qftp::login){
ui->label->settext(tr("正在登入..."));
if (ftp->currentcommand() == qftp::get){
ui->label->settext(tr("正在下載下傳..."));
else if (ftp->currentcommand() == qftp::close){
ui->label->settext(tr("正在關閉連接配接..."));
}
每當指令執行時,都會執行ftpcommandstarted()函數,它有一個參數int id,這個id就是調用指令時傳回的id,如int
loginid= ftp->login(); 這時,我們就可以用if(id == loginid)來判斷執行的是否是login()函數。但是,我們不想為每個指令都設定一個變量來存儲其傳回值,是以,我們這裡使用了ftp->currentcommand() ,它也能擷取目前執行的指令的類型。在這個函數裡我們讓開始不同的指令時顯示不同的狀态資訊。
void widget::ftpcommandfinished(int,bool error)
if(error)
ui->label->settext(tr("連接配接伺服器出現錯誤:%1")
.arg(ftp->errorstring()));
else ui->label->settext(tr("連接配接到伺服器成功"));
ui->label->settext(tr("登入出現錯誤:%1")
else ui->label->settext(tr("登入成功"));
ui->label->settext(tr("下載下傳出現錯誤:%1")
else {
ui->label->settext(tr("已經完成下載下傳"));
ui->textbrowser->settext(ftp->readall());
}
ui->label->settext(tr("已經關閉連接配接"));
這個函數與ftpcommandstarted()函數相似,但是,它是在一個指令執行結束時執行的。它有兩個參數,第一個intid,就是調用指令時傳回的編号,我們在上面已經講過了。第二個是bool
error,它标志現在執行的指令是否出現了錯誤。如果出現了錯誤,那麼error 為true ,否則為false。我們可以利用它來輸出錯誤資訊。在這個函數中,我們在完成一條指令時顯示不同的狀态資訊,并顯示可能的出錯資訊。在if
(ftp->currentcommand() == qftp::get) 中,也就是已經完成下載下傳時,我們讓textbrowser顯示下載下傳的資訊。
6.運作程式,效果如下。
7.出錯示範。
下面我們示範一下出錯時的情況。
将構造函數中的代碼ftp->login();改為ftp->login("tom","123456");
這時我們再運作程式:
可以看到,它輸出了錯誤資訊,指明了錯誤的指令和出錯的内容。其實我們設定的這個錯誤,也是想告訴大家,在ftp中如果沒有設定使用者名和密碼,那麼預設的使用者名應該是anonymous,這時密碼可以任意填寫,而使用其他使用者名是會出錯的。
結語
在下一節中,我們将會對這個程式進行擴充,讓它可以浏覽伺服器上的所有檔案,并進行下載下傳。
涉及的源碼下載下傳:
kb, 下載下傳次數: 1)