Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Скан фтп-дерева  (Прочитано 12260 раз)
0 Пользователей и 3 Гостей смотрят эту тему.
tripout
Гость
« : 18-03-2005 12:15 » 

Вопросик:
Код:
void ScanFTP(TCHAR *szServerName, LPSTR szPathSpec)
{
HINTERNET hOpen = NULL,hInet=NULL,hFTP=NULL;
WIN32_FIND_DATA FindFileData;
memset ((char *)&FindFileData, 0, sizeof(FindFileData));
char Buffer[MAX_PATH+1]={0};
hInet = InternetOpen(TEXT("FTP Scanner"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (hInet!=NULL){
 hFTP = InternetConnect (hInet, szServerName, INTERNET_DEFAULT_FTP_PORT, NULL, NULL, INTERNET_SERVICE_FTP, 0, 0);
 if (hFTP!=NULL){
  hOpen = FtpFindFirstFile(hFTP, szPathSpec, &FindFileData, INTERNET_FLAG_NO_CACHE_WRITE, 0);
  if(hOpen!=NULL){
   do{
    if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
     if(!(stricmp(FindFileData.cFileName,".")==0 || stricmp(FindFileData.cFileName,"..")==0)){
      strcpy(Buffer,szPathSpec);
      strcat(Buffer,"/");
      strcat(Buffer,FindFileData.cFileName);
      ScanFTP(szServerName ,Buffer);
     }
    } else {
     // имеем имя файла с путём...
    }
   } while (InternetFindNextFile(hOpen, &FindFileData));
   InternetCloseHandle (hOpen);
  }
  InternetCloseHandle (hFTP);
 }
 InternetCloseHandle (hInet);
}
}
Вот этот код сканит дерево каталогов на удалённом фтп-сервере.
Но здесь на каждую вложенную папку создаётся дополнительное соединение.
А на многих фтп стоит ограничение на количество соединений с одного ип.
Можно ли как-то уложиться в 1, максимум в 2 соединения?
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #1 : 18-03-2005 14:18 » 

У тебе рекурсия в цикле. вынеси цикл в другую ф-ю, которую и сделай рекурсивной.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
tripout
Гость
« Ответ #2 : 18-03-2005 16:01 » 

Не всё так просто... На один InternetConnect можно вызывать FtpFindFirstFile только один раз. Жаль
Записан
Hooter
Опытный

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 18-03-2005 19:18 » 

Можно сделать так:
1. создаёшь сессию (InternetConnect)
2. выполняешь цикл FtpFindFirstFile-InternetFindNextFile.
    в цикле создаешь список директорий в текущей папке
3. удаляешь сессию (InternetCloseHandle)
4. выполняешь цикл - для каждого элемента списка вызываешь ScanFTP

Таким образом получается, что у тебя вообще только одна сессия все время открыта.
Записан
Hooter
Опытный

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 18-03-2005 19:21 » 

ЗЫ. Если бы код был отформатирован, то читать его было бы гораздо легче.
Записан
tripout
Гость
« Ответ #5 : 18-03-2005 21:14 » new

Хм... ну тогда вопрос немного не в тему: а как сделать массив для имён папок, причём неизвестной заранее длины и выделить для него память?
Простите чайника, если вопрос глупый, но я даже и не представляю, как...
Записан
Hooter
Опытный

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 18-03-2005 22:29 » 

ну... разные есть способы... в зависимости от того, с помощью какой библиотеки прогу пишешь...

В MFC например, есть класс CString и класс-контейнер CArray. В библиотеке STL есть класс string и классы-контейнеры vector и list. Ну и в борланде че-то там есть Ага
Ежели на голом Си пишешь, то тут, конечно, всё сложнее... Но, имхо, лучше использовать готовое решение, чем тратить время на изобретение велосипеда.

Я лично предпочитаю библиотеку STL. Во-первых, никаких дополнительных DLL не надо с EXEшником предоставлять. Во-вторых, достаточно легкий и читабельный код получается. В-третьих, является стандартом ANSI С++, а следовательно код, использующий STL, должен без проблем компилироваться разными компиляторами (хоть MSVC, хоть в борланде, хоть gcc). Вообще, старайся придерживаться стандартов, если нет каких-то специальных условий. Увидишь, жить и работать станет намного легче Улыбаюсь

ЗЫ. Сорри за филофофию
Записан
tripout
Гость
« Ответ #7 : 19-03-2005 08:57 » 

Если не сложно, можно примерчик на эту тему с использованием STL. Как назло, ни одного примера с ним нету... Желательно с комментами Ага

ЗЫ. Пишу на борланде, STL есть.
Записан
Hooter
Опытный

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 21-03-2005 18:28 » 

Давай я тебе примерчик прям в твоем коде и напишу? Улыбаюсь

Я сначала попытаюсь объяснить вкратце...
В библиотеке STL есть некие классы, которые могут хранить внутри себя наборы объектов. Такие классы называются контейнерами.
В частности, есть такой контейнер - vector.
Также есть класс, облегчающий работу с символьными строками - string.
Попытаемся решить твою задачу, используя контейнер vector, который будет хранить объекты типа string.

Итак, для начала нужно подключить необходимые заголовочные файлы: <vector> и <string>.
Код:
#include <vector>
#include <string>

Теперь необходимо создать экземпляр контейнера vector, который и будет нашим массивом имён директорий:
Код:
std::vector<std::string> folders;
или
Код:
using namespace std;
vector<string> folders;
Здесь в треугольных скобках мы указываем тип объектов, которые будут храниться в контейнере.
Самому массиву, как видно из кода, мы присвоили имя folders.

При работе с библиотекой STL приветсвуется использование typedef.
Поэтому вместо описанного выше кода можно написать следующее:
Код:
typedef std::vector<std::string> CStringVector;
CStringVector folders;

Для добавления нового элемента к концу массива можно использовать метод vector::push_back(...):
Код:
folders.push_back("Новый элемент");
char str[] = "Еще один новый элемент";
folders.push_back(str);
std::string str2 = "А вот и еще новый элемент";
folders.push_back(str2);

Для получения текущего количесва элементов массиве существует метод size():
Код:
int count = folders.size();

Для получения конкретного элемента с индексом i можно использовать оператор []:
Код:
int i = 0;
std::string str3 = folders[i];
std::string str4 = folders[2];

Да, чуть не забыл: для преобразования объекта типа string к типу (const char *) необходимо вызвать метод c_str():
Код:
std::string str = "строка";
const char *ptr = str.c_str();
const char *ptr2 = folders[0].c_str();

Теперь попытаемся решить твою задачу.
Я выбрал класс vector из тех соображений, что в нем есть возможность доступа к элементам массива по их индексу - folders[index].
Это не единственный и далеко не лучший способ использования vector<string>. И это далеко не лучший вариант решения этой задачи.
Но, имхо, так как ты раньше не сталкивался с STL, то наверное этот код будет тебе более понятен, чем какой-либо другой.
Код:
#include <vector>
#include <string>

void ScanFTP(TCHAR *szServerName, const char *szPathSpec)
{
// Создаем массив строк
std::vector<std::string> folders;

HINTERNET hOpen = NULL,hInet=NULL,hFTP=NULL;
WIN32_FIND_DATA FindFileData;
memset ((char *)&FindFileData, 0, sizeof(FindFileData));
char Buffer[MAX_PATH+1]={0};
hInet = InternetOpen(TEXT("FTP Scanner"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (hInet!=NULL)
{
hFTP = InternetConnect (hInet, szServerName, INTERNET_DEFAULT_FTP_PORT, NULL, NULL, INTERNET_SERVICE_FTP, 0, 0);
if (hFTP!=NULL)
{
hOpen = FtpFindFirstFile(hFTP, szPathSpec, &FindFileData, INTERNET_FLAG_NO_CACHE_WRITE, 0);
if(hOpen!=NULL)
{
do
{
if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (strcmp(FindFileData.cFileName, ".") && strcmp(FindFileData.cFileName, ".."))
{
// Формируем полное имя папки
std::string name = szPathSpec;
name += "/";
name += FindFileData.cFileName;

// Добавляем имя найденной папки
// в конец массива:
folders.push_back(name);
}
}
else
{
// имеем имя файла с путём...
}
}
while (InternetFindNextFile(hOpen, &FindFileData));
InternetCloseHandle (hOpen);
}
InternetCloseHandle (hFTP);
}
InternetCloseHandle (hInet);

// Я не знаю, в каком именно месте у тебя должен быть
// этот код, но предположим, что здесь...
// Для каждого элемента вектора folders вызываем ScanFTP.
int i = folders.size();
while (i--)
{
// Передаем в scanFtp строку
// из массива folders с индексом count.
ScanFTP(szServerName, folders[i].c_str());
}

}
}
« Последнее редактирование: 21-03-2005 18:39 от Hooter » Записан
tripout
Гость
« Ответ #9 : 21-03-2005 20:55 » 

Офигенно! Респект! Более понятно я бы вряд-ли смог где найти!

А жил бы ты в Новосибирске, я б ещё и пивом напоил Ага
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines