08 cerr << "Error: URL must start with 'ftp:'" << endl;
09 return false;
10 }
11 ftp.connectToHost(url.host, url.port(21));
12 ftp.login;
13 QString path = url.path;
14 if (path.isEmpty)
15 path = "/";
16 pendingDirs.append(path);
17 processNextDirectory;
18 return true;
19 }
Выполнение
функции getDirectory начинается с некоторых основных проверок, и если все нормально, делается попытка установить FTP—соединение. Она отслеживает пути, которые необходимо будет обрабатывать, и вызывает функцию processNextDirectory, чтобы начать скачивание корневого каталога.
01 void Spider::processNextDirectory
02 {
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, обозначающий завершение скачивания.
информацию о файле в сети. Если это обычный файл (не каталог) и его можно считывать, мы вызываем функцию get для его загрузки. Объект QFile, используемый для загрузки файла, создается с помощью оператора new, и указатель на него хранится в списке openedFiles.
Если содержащиеся в QUrlInfo сведения об удаленном каталоге говорят, что он не является символической связью, этот каталог добавляется к списку pendingDirs. Мы пропускаем символические связи, поскольку они легко могут привести к бесконечной рекурсии.
Слот 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)
list
emit listInfo(file_N_1)
get(file_N_1)
emit listInfo(file_N_2)
get(file_N_2)
…
emit done
Если файл фактически оказывается каталогом, он добавляется в список pendingDirs и, когда завершается скачивание последнего файла, полученного текущей командой list, выдается новая команда cd, за которой следует новая команда list для следующего каталога, ожидающего обработки, и весь процесс повторяется для нового каталога. Скачиваются новые файлы, и в список pendingDirs добавляются новые каталоги до тех пор, пока не будут скачаны все файлы из всех каталогов и список pendingDirs в результате не станет пустым.