03 if (!pendingDirs.isEmpty()) {

04 currentDir = pendingDirs.takeFirst();

05 currentLocalDir = "downloads/" + currentDir;

06 QDir(".").mkpath(currentLocalDir);

07 ftp.cd(currentDir);

08 ftp.list();

09 } else {

10 emit done();

11 }

12 }

Функция processNextDirectory() принимает первый удаленный каталог из списка каталогов, ожидающих обработки, pendingDirs, и создает соответствующий каталог в локальной файловой системе. После этого она указывает объекту QFtp на необходимость изменения каталога на принятый ею каталог и затем получения списка его файлов. Для каждого файла, обрабатываемого функцией list(), генерируется сигнал listInfo(), приводящий к вызову слота ftpListInfo().

Когда все каталоги оказываются обработанными, эта функция генерирует сигнал done(), обозначающий завершение скачивания.

01 void Spider::ftpListInfo(const QUrlInfo &urlInfo)

02 {

03 if (urlInfo.isFile()) {

04 if (urlInfo.isReadable()) {

05 QFile *file = new QFile(currentLocalDir + "/"

06 + urlInfo.name());

07 if (!file->open(QIODevice::WriteOnly)) {

08 cerr << "Warning: Cannot open file << qPrintable(

09 QDir::convertSeparators(file->fileName()))

10 << endl;

11 return;

12 }

13 ftp.get(urlInfo.name(), file);

14 openedFiles.append(file);

15 }

16 } else if (urlInfo.isDir() && !urlInfo.isSymLink()) {

17 pendingDirs.append(currentDir + "/" + urlInfo.name());

18 }

19 }

Параметр urlInfo слота ftpListInfo() содержит информацию о файле в сети. Если это обычный файл (не каталог) и его можно считывать, мы вызываем функцию get() для его загрузки. Объект QFile, используемый для загрузки файла, создается с помощью оператора new, и указатель на него хранится в списке openedFiles.

Если содержащиеся в QUrlInfo сведения об удаленном каталоге говорят, что он не является символической связью, этот каталог добавляется к списку pendingDirs. Мы пропускаем символические связи, поскольку они легко могут привести к бесконечной рекурсии.

01 void Spider::ftpDone(bool error)

02 {

03 if (error) {

04 cerr << "Error: " << qPrintable(ftp.errorString()) << endl;

05 } else {

06 cout << "Downloaded " << qPrintable(currentDir) << " to "

07 << qPrintable(QDir::convertSeparators(

08 QDir(currentLocalDir).canonicalPath()));

09 }

10 qDeleteAll(openedFiles);

11 openedFiles.clear();

12 processNextDirectory();

13 }

Слот ftpDone() вызывается после завершения всех команд FTP или при возникновении ошибки. Мы удаляем объекты QFile для предотвращения утечек памяти, а также для закрытия всех файлов. Наконец, мы вызываем функцию processNextDirectory(). Если какие-нибудь каталоги остались, весь процесс повторяется для следующего каталога в списке; в противном случае скачивание файлов прекращается и генерируется сигнал done().

Если ошибок нет, последовательность команд FTP и сигналов будет такой:

connectToHost(host, port)

login()

cd(directory_1)

list()

emit listInfo(file_1_1)

get(file_1_1)

emit listInfo(file_1_2)

get(file_1_2)

emit done()

cd(directory_N)

Перейти на страницу:

Похожие книги