上一節我們講述了HTTP的編程,這一節講述與其及其相似的FTP的編程。FTP即File Transfer Protocol,也就是檔案傳輸通訊協定。FTP的主要作用,就是讓使用者串連上一個遠端電腦,查看遠端電腦有哪些檔案,然後把檔案從遠端電腦上拷貝到本機電腦,或者把本機電腦的檔案送到遠端電腦上。
在Qt中,我們可以使用上一節講述的QNetworkAccessManager和QNetworkReply類來進行FTP 程式的編寫,因為它們用起來很簡單。但是,對於較複雜的FTP操作,Qt還提供了QFtp類,利用這個類,我們很容易寫出一個FTP用戶端程式。下面我們先在協助中查看這個類。
在QFtp中,所有的操作都對應一個特定的函數,我們可以稱它們為命令。如connectToHost()串連到伺服器命令,login()登入命令,get()下載命令,mkdir()建立目錄命令等。因為QFtp類以非同步方式工作,所以所有的這些函數都不是阻塞函數。也就是說,如果一個操作不能立即執行,那麼這個函數就會直接返回,直到程式控制權返回Qt事件迴圈後才真正執行,它們不會影響介面的顯示。
所有的命令都返回一個int 型的編號,使用這個編號讓我們可以跟蹤這個命令,查看其執行狀態。當每條命令開始執行時,都會發出commandStarted()訊號,當該命令執行結束時,會發出commandFinished()訊號。我們可以利用這兩個訊號和命令的編號來擷取命令的執行狀態。當然,我們不想執行每條命令都要記下它的編號,所以我們也可以使用currentCommand()來擷取現在執行的命令,其傳回值與命令的對應關係如。
下面我們先看一個簡單的FTP用戶端的例子,然後對它進行擴充。
在這個例子中我們從FTP伺服器上下載一個檔案並顯示出來。
1.我們建立Qt4 Gui QApplication 。
工程名為“myFtp”,然後選中QtNetwork模組,最後Base class選擇QWidget 。
2.修改widget.ui檔案。
在其中添加一個Text Browser 和一個 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.nokia.com”); //串連到伺服器
ftp->login(); //登入
ftp->cd(“qt”); //跳轉到“qt”目錄下
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(ftp->currentCommand() == QFtp::ConnectToHost){
if(error) ui->label->setText(tr(“串連伺服器出現錯誤:%1″).arg(ftp->errorString()));
else ui->label->setText(tr(“串連到伺服器成功”));
}
if (ftp->currentCommand() == QFtp::Login){
if(error) ui->label->setText(tr(“登入出現錯誤:%1″).arg(ftp->errorString()));
else ui->label->setText(tr(“登入成功”));
}
if (ftp->currentCommand() == QFtp::Get){
if(error) ui->label->setText(tr(“下載出現錯誤:%1″).arg(ftp->errorString()));
else {
ui->label->setText(tr(“已經完成下載”));
ui->textBrowser->setText(ftp->readAll());
}
}
else if (ftp->currentCommand() == QFtp::Close){
ui->label->setText(tr(“已經關閉串連”));
}
}
這個函數與ftpCommandStarted()函數相似,但是,它是在一個命令執行結束時執行的。它有兩個參數,第一個int id,就是調用命令時返回的編號,我們在上面已經講過了。第二個是bool error,它標誌現在執行的命令是否出現了錯誤。如果出現了錯誤,那麼error 為true ,否則為false。我們可以利用它來輸出錯誤資訊。在這個函數中,我們在完成一條命令時顯示不同的狀態資訊,並顯示可能的出錯資訊。在if (ftp->currentCommand() == QFtp::Get) 中,也就是已經完成下載時,我們讓textBrowser顯示下載的資訊。
6.運行程式,效果如下。
登入狀態。
下載完成後。
7.出錯示範。
下面我們示範一下出錯時的情況。
將建構函式中的代碼ftp->login();改為ftp->login(“tom”,”123456″);
這時我們再運行程式:
可以看到,它輸出了錯誤資訊,指明了錯誤的指令和出錯的內容。其實我們設定的這個錯誤,也是想告訴大家,在FTP中如果沒有設定使用者名稱和密碼,那麼預設的使用者名稱應該是anonymous,這時密碼可以任意填寫,而使用其他使用者名稱是會出錯的。
在下一節中,我們將會對這個程式進行擴充,讓它可以瀏覽伺服器上的所有檔案,並進行下載。