информацию о файле в сети. Если это обычный файл (не каталог) и его можно считывать, мы вызываем функцию 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 в результате не станет пустым.
Если возникнет сетевая ошибка при загрузке пятого файла, скажем, из двадцати файлов в каталоге, остальные файлы не будут скачаны. Если бы мы захотели скачать как можно больше файлов, то один из способов заключается в выполнении по одной операции GET и ожидании сигнала done(bool) перед выполнением новой операции GET. В функции listInfo мы бы просто добавили имя файла в конец списка QStringList вместо немедленного вызова get, а в слоте done(bool) мы бы вызывали функцию get для следующего загружаемого файла из списка QStringList. Последовательность команд выглядела бы так:
connectToHost(host, port)
login
cd(directory_1)
list
…
cd(directory_N)
list
emit listInfo(file_1_1)
emit listInfo(file_1_2)
…
emit listInfo(file_N_1)
emit listInfo(file_N_2)
…
emit done
get(file_1_1)
emit done
get(file_1_2)
emit done
…
get(file_N_1)
emit done
get(file_N_2)
emit done
…
Еще одно решение могло бы заключаться в применении одного объекта QFtp для каждого файла. Это позволило бы нам скачивать файлы из сети параллельно, используя отдельные FTP—соединения.