在Qt中,与文件传输协议(FTP)相对应的类为QFtp。在这个类中,提供了许多与文件上传和下载有关的方法,这使得文件的上传与下载变得十分方便。本文所描述的FTP客户端的基本使用方法是:首先输入正确的FTP服务器地址,用户名以及密码;登录成功后将显示服务器中的文件列表;点击下载按钮对某个文件进行下载。用户界面可参考下图:

用户界面设计可见本文参考1和参考2,接下来将对具体的实现过程进行分析。
构造函数
在构造函数中,对用户界面进行了初始化,并隐藏了进度显示条。除此之外,还将itemActivated信号和processItem槽函数进行了连接。当用户双击(或单击,依据具体OS)TreeWidget中的某一条信息时,QTreeWidget类的对象fileList就会发送itemActivated信号。
01 | Widget::Widget(QWidget *parent) : |
06 | ui->progressBar->setValue(0); |
08 | connect(ui->fileList, SIGNAL(itemActivated(QTreeWidgetItem*, int )), |
09 | this , SLOT(processItem(QTreeWidgetItem*, int ))); |
on_connectButton_clicked()的实现
在连接按钮单击事件的槽函数中主要完成了两部分工作:登录FTP服务器以及几个信号和槽函数之间的连接,这几个信号均由FTP对象发出。当FTP命令开始执行时,便发出commandStarted信号;当FTP的命令执行完毕时,便发出commandFinished信号;当使用list命令列表显示目录的内容时候,listInfo信号将发出;最后在数据传输的过程中,会不断的发出dataTransferProgress信号以便更新进度显示条。
由于QFtp类中封装了许多与FTP有关成员函数,因此使用connectToHost成员函数可以登录到FTP服务器,使用login函数可以登录到服务器。
01 | void Widget::on_connectButton_clicked() |
03 | ui->fileList->clear(); |
08 | connect(ftp, SIGNAL(commandFinished( int , bool )), |
09 | this , SLOT(ftpCommandFinished( int , bool ))); |
10 | connect(ftp, SIGNAL(listInfo(QUrlInfo)), this , SLOT(addToList(QUrlInfo))); |
11 | connect(ftp, SIGNAL(dataTransferProgress(qint64,qint64)), |
12 | this , SLOT(updateDataTransferProgress(qint64,qint64))); |
14 | QString ftpServer = ui->ftpServerLineEdit->text(); |
15 | QString userName = ui->userNameLineEdit->text(); |
16 | QString passWord = ui->passWordLineEdit->text(); |
18 | ftp->connectToHost(ftpServer, 21); |
19 | ftp->login(userName, passWord); |
ftpCommandFinished()的实现
当FTP命令执行完毕后,将执行ftpCommandFinished函数。与本文所描述的命令有ConnectToHost()、Login()、Get()、Close()和List()。通过currentCommand成员函数可以具体得到当前执行完毕命令的id,因此根据不同命令的id在用户界面上显示不同的命令状态。
01 | void Widget::ftpCommandFinished( int , bool error) |
03 | if (ftp->currentCommand() == QFtp::ConnectToHost) { |
05 | ui->label->setText(tr( "connecting error %1" ).arg(ftp->errorString())); |
07 | ui->label->setText(tr( "connecting success!" )); |
10 | if (ftp->currentCommand() == QFtp::Login) { |
12 | ui->label->setText(tr( "login error" ).arg(ftp->errorString())); |
14 | ui->label->setText(tr( "login success!" )); |
on_downloadButton_clicked()的实现
当单击下载按钮后,将进入该函数进行相应文件的下载。首先通过fileList对象中的成员函数得到要下载文件的名称,在打开该文件,最后通过get函数获取数据。
01 | void Widget::on_downloadButton_clicked() |
03 | QString fileName = ui->fileList->currentItem()->text(0); |
04 | file = new QFile(fileName); |
05 | if (!file->open(QIODevice::WriteOnly)) { |
10 | ui->downloadButton->setEnabled( false ); |
11 | ftp->get(ui->fileList->currentItem()->text(0), file); |
addToList()的实现
当对FTP服务器上某个目录执行list()命令时,对于list()找到的每一个文件都会发出listInfo()信号。该信号会使得addToList函数执行,以便在treeWidget上增加一条新的文件信息。
因此,该函数首先根据urlInfo参数建立一条新的文件信息,然后再利用addTopLevelItem成员函数将该条新的文件信息加入到treeWidget最顶端。
01 | void Widget::addToList( const QUrlInfo &urlInfo) |
03 | QTreeWidgetItem *item = new QTreeWidgetItem; |
04 | item->setText(0, urlInfo.name()); |
05 | item->setText(1, QString::number(urlInfo.size())); |
06 | item->setText(2, urlInfo.owner()); |
07 | item->setText(4, urlInfo.lastModified().toString( "mmm dd yyyy" )); |
08 | QPixmap pixmap(urlInfo.isDir() ? "../dir.png" : "../file.png" ); |
09 | item->setIcon(0, pixmap); |
10 | isDirectory[urlInfo.name()] = urlInfo.isDir(); |
13 | ui->fileList->addTopLevelItem(item); |
14 | if (!ui->fileList->currentItem()) { |
15 | ui->fileList->setCurrentItem(ui->fileList->topLevelItem(0)); |
16 | ui->fileList->setEnabled( true ); |
processItem()的实现
当双击文件列表中某一项时候,如果该项所显示的文件为目录,则进入该目录中显示其内部的文件列表。上述的内容即为processItem函数所要完成的工作。
01 | void Widget::processItem(QTreeWidgetItem *item, int ) |
04 | QString name = item->text(0); |
05 | if (isDirectory.value(name)) { |
06 | ui->fileList->clear(); |
12 | ui->cdToParentButton->setEnabled( true ); |
updateDataTransferProgress()的实现
每当FTP服务器端的数据返回时,就引发该函数的执行。该函数的主要工作即更新进度条的显示。
1 | void Widget::updateDataTransferProgress(qint64 readBytes, qint64 totalBytes) |
3 | ui->progressBar->setMaximum(totalBytes); |
4 | ui->progressBar->setValue(readBytes); |
未完待续~
参考:
1. Qt Assistant
2. http://www.yafeilinux.com/?p=757
3. C++ GUI Qt 4编程(第二版); 电子工业出版社;Blanchette,J,Summerfield,M 著;闫锋欣 等译;