详细说明:
《 C++ GUI Qt 4编程(第二版)》第十五章15.1节Spider命令行程序,即在P273页。这个例子代码如下:
main.cpp:
#include <QtCore>
#include <iostream>
#include "spider.h"
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QStringList args = QCoreApplication::arguments();
if (args.count() != 2) {
std::cerr << "Usage: spider url" << std::endl
<< "Example:" << std::endl
<< " spider
ftp://ftp.trolltech.com/freebies/"
<< "leafnode" << std::endl;
return 1;
}
Spider spider;
if (!spider.getDirectory(QUrl(args[1])))
return 1;
QObject::connect(&spider, SIGNAL(done()), &app, SLOT(quit()));
return app.exec();
}
Spider.h
a#ifndef SPIDER_H
#define SPIDER_H
#include <QFtp>
#include <QStringList>
class QFile;
class Spider : public QObject
{
Q_OBJECT
public:
Spider(QObject *parent = 0);
bool getDirectory(const QUrl &url);
signals:
void done();
private slots:
void ftpDone(bool error);
void ftpListInfo(const QUrlInfo &urlInfo);
private:
void processNextDirectory();
QFtp ftp;
QList<QFile *> openedFiles;
QString currentDir;
QString currentLocalDir;
QStringList pendingDirs;
};
#endif // SPIDER_H
Spider.cpp
#include <QtCore>
#include <QtNetwork>
#include <iostream>
#include "spider.h"
Spider::Spider(QObject *parent)
: QObject(parent)
{
connect(&ftp, SIGNAL(done(bool)), this, SLOT(ftpDone(bool)));
connect(&ftp, SIGNAL(listInfo(const QUrlInfo &)), this, SLOT(ftpListInfo(const QUrlInfo &)));
}
bool Spider::getDirectory(const QUrl &url)
{
if (!url.isValid()) {
std::cerr << "Error: Invalid URL" << std::endl;
return false;
}
if (url.scheme() != "ftp") {
std::cerr << "Error: URL must start with 'ftp:'" << std::endl;
return false;
}
ftp.connectToHost(url.host(), url.port(21));
ftp.login();
QString path = url.path();
if (path.isEmpty())
path = "/";
pendingDirs.append(path);
processNextDirectory();
return true;
}
void Spider::ftpDone(bool error)
{
if (error) {
std::cerr << "Error: " << qPrintable(ftp.errorString())
<< std::endl;
} else {
std::cout << "Downloaded " << qPrintable(currentDir) << " to "
<< qPrintable(QDir::toNativeSeparators(
QDir(currentLocalDir).canonicalPath()));
}
qDeleteAll(openedFiles);
openedFiles.clear();
processNextDirectory();
}
void Spider::ftpListInfo(const QUrlInfo &urlInfo)
{
if (urlInfo.isFile()) {
if (urlInfo.isReadable()) {
QFile *file = new QFile(currentLocalDir + "/"
+ urlInfo.name());
if (!file->open(QIODevice::WriteOnly)) {
std::cerr << "Warning: Cannot write file "
<< qPrintable(QDir::toNativeSeparators(
file->fileName()))
<< ": " << qPrintable(file->errorString())
<< std::endl;
return;
}
ftp.get(urlInfo.name(), file);
openedFiles.append(file);
}
} else if (urlInfo.isDir() && !urlInfo.isSymLink()) {
pendingDirs.append(currentDir + "/" + urlInfo.name());
}
}
void Spider::processNextDirectory()
{
if (!pendingDirs.isEmpty()) {
currentDir = pendingDirs.takeFirst();
currentLocalDir = "downloads/" + currentDir;
QDir(".").mkpath(currentLocalDir);
ftp.cd(currentDir);
ftp.list();
} else {
emit done();
}
}
我的操作系统为UBUNTU10.04,KDE为QT4.6.2。
我的main函数参数设置,即args[]为:第一个是工程所在位置,第二个是目标文件夹所在位置,即
ftp://home/zhaocong/Downloads。Downloads下有文件。运行之后,发现不仅只下载了Downloads文件夹,而且还下载了home,zhaocong两个文件夹,而Downloads中的文件一个没有下载。
我分析了一下,发现spider.cpp的processNextDirectory()中的ftp.list()没有执行。按照QFtp中list()函数的描述,list()会触发listInfo()信号,进而通过信号和槽运行spider.cpp中的ftpListInfo()函数。但是通过单步运行,发现没有执行list()。