Listowanie plików/katalogów z FTP - wininet

problemy z tworzeniem programów do obsługi sieci, internetu, e-mail itp..

Listowanie plików/katalogów z FTP - wininet

Nowy postprzez mckri » czwartek, 24 grudnia 2009, 11:36

Witam.
Tworzę mały programik do łączenia się z ftp i przeszukiwania jego podkatalogów wzgledem podanej lokalizacji. Do ftp łącze się używając biblioteki wininet.
Pliki lub katalogi z jednej podanej lokalizacji, bez problemu mogę wylistować . Zaciąłem sie na tym, że nie moge dać rady z wylistowaniem podkatalogów i znajdujących się w nich plików. Korzystam z BCB 2009.
Prosiłbym o pomoc i podpowiedź jak zrobić rekurencyjne wywoływanie funkcji 'ListujFtp', tak aby można było listować pliki i podkatalogi względem podanej lokalizacji. Najprawdopodobniej obecna kontrukcja funkcji nie pozwala na rekurencyjne wywoływanie (problem z uchwytem 'hFile'), ale nie wiem jak to zrobić.
Poniżej przydstawiam kompletne, działające funkcje łączenia się i listowania plików/katalogów z podanej lokalizacji:

Kod: Zaznacz cały
HINTERNET hFind, hOpen, hConnect; //globalnie - uchwyty

void __fastcall PolaczFtp(String Host, String Login, String Pass)  //łaczenie z ftp
{
  hOpen = InternetOpen(ParamStr(0).t_str(), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
  if(hOpen==0)
  {
      ShowMessage("Brak możliwości otworzenia połączenia internetowego");
  }

  hConnect = InternetConnect(hOpen, Host.t_str(),21,Login.t_str(),Pass.t_str() ,INTERNET_SERVICE_FTP, 0, 0);
  if(hConnect==0)
  {
      ShowMessage("Nie można połączyć z: "+Host);
  }
  else
  {
      ShowMessage("Połączony z: "+Host);
  }
}
//----------------------------------------------------------------------------
void __fastcall ListujFtp(TListBox *Lista, String Dir)  //listowanie plików/katalogów
{
  WIN32_FIND_DATA w32fd;

  if (hConnect!=0)
  {
     try
     {
       hFind = FtpFindFirstFile(hConnect,Dir.t_str(), &w32fd,  INTERNET_FLAG_RELOAD, 0);   //INTERNET_FLAG_RELOAD lub INTERNET_FLAG_NO_CACHE_WRITE, szczegóły na TechNet
       if(hFind!=0)
       {
        try
        {
         do
         {
           if((w32fd.dwFileAttributes==FILE_ATTRIBUTE_DIRECTORY) & ((String)w32fd.cFileName!=".") & ((String)w32fd.cFileName!="..")) //obiekt jest katalogiem
           {
              Lista->Items->Add("[DIR]"+(String)w32fd.cFileName);    //tutaj listuje katalogi
           }
           else if(w32fd.dwFileAttributes!=FILE_ATTRIBUTE_DIRECTORY)
           {
             Lista->Items->Add((String)w32fd.cFileName);    //tutaj listuje pliki
           }
//tutaj gdzie trzeba by było wstawic funcje rekurencyjnego wołania tej funkcji, ale miałem z tym problem
         }
         while(InternetFindNextFile(hFind, &w32fd));

        }
        __finally
        {
         InternetCloseHandle(hFind);
        }
       }
       else
       {
         ShowMessage("Problem z uchwytem hFind!");  //TUTAJ JEST PROBLEM PRZY REKURENCYJNYM WOŁANIU FUNKCJI 'ListujFtp'
       }
     }
     __finally
     {  }
  }
  else
  {
   ShowMessage("Brak połączenia z: "+Host);
  }
}
//----------------------------------------------------------------------------
void __fastcall RozlaczFtp(void)   //rozłaczanie z Hostem
{
   if(hConnect!=0) InternetCloseHandle(hConnect);
   if(hOpen!=0) InternetCloseHandle(hOpen);
}
//----------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)  //zestawienie połączenia
{
  PolaczFtp(Edit1->Text,Edit2->Text,Edit3->Text);  //podaje dane do połączenia z ftp.
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)  //rozłączenie z ftp
{
   RozlaczFtp();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)     //wywołanie funkcji listowania plików/katalogów na ftp
{
  ListBox1->Clear();
  ListujFtp(ListBox1,Edit4->Text);  //tutaj podaje lokalizacje katalogu, który chce przeszukac
}
//---------------------------------------------------------------------------


Bedę wdzięczny za pomoc.
Avatar użytkownika
mckri
Intelektryk
Intelektryk
 
Posty: 160
Dołączył(a): piątek, 15 sierpnia 2008, 13:48
Podziękował : 10
Otrzymał podziękowań: 2
System operacyjny: Windows Vista SP2
Kompilator: BCB 5/2007/2009
    NieznanyNieznana

Re: Listowanie plików/katalogów z FTP - wininet

Nowy postprzez Cyfrowy Baron » czwartek, 24 grudnia 2009, 12:58

Nie chce mi się tego dziś sprawdzać, bo wigilia i wogóle, ale wywołanie rekurencyjne to powinieneś robić wewnątrz warunku wyliczającego katalogi, a nie poza wszelkimi warunkami. Poza tym podając jako argument Dir funkcji powinieneś podać wyliczony katalog

Kod: Zaznacz cały
if( (w32fd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) &
     ((String)w32fd.cFileName != ".") & ((String)w32fd.cFileName != "..") )
           {
              ListujFtp(Lista, Dir + (String)w32fd.cFileName + "\\")
             /* lub ListujFtp(Lista, Dir + "\\" + (String)w32fd.cFileName + "\\"),
                 lub ListujFtp(Lista, Dir + "\\" + (String)w32fd.cFileName),
                 lub ListujFtp(Lista, Dir + (String)w32fd.cFileName),
                 zależy od tego jak masz to skonstruowane, sam to sprawdź,
                 ale rekurencja powinna występować właśnie w tym miejscu
              */
              Lista->Items->Add("[DIR]" + (String)w32fd.cFileName);
           }
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4728
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 444
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: Listowanie plików/katalogów z FTP - wininet

Nowy postprzez mckri » czwartek, 24 grudnia 2009, 13:25

Tak jak to proponujesz juz sprawdzałem wczesniej. Przy takim włąsnie wywołaniu funkcji ListujFtp 'gubiony' jest uchwyt do hFile. Faktycznie źle ten fragment opisałem w poście.
Avatar użytkownika
mckri
Intelektryk
Intelektryk
 
Posty: 160
Dołączył(a): piątek, 15 sierpnia 2008, 13:48
Podziękował : 10
Otrzymał podziękowań: 2
System operacyjny: Windows Vista SP2
Kompilator: BCB 5/2007/2009
    NieznanyNieznana

Re: Listowanie plików/katalogów z FTP - wininet

Nowy postprzez Cyfrowy Baron » czwartek, 24 grudnia 2009, 14:39

Co dokładnie rozumiesz przez gubiony uchwyt i gdzie jest zmienna-obiekt hFile w Twoim kodzie, bo ja czegoś takiego nie widzę?

Błąd może powodować metoda _finally (try -> _finally), gdyż w odróżnieniu od catch, __finally jest wykonywane niezależnie od tego, czy try "się udało", czy nie, więc blok się wykonuje i zakańcza działanie, wywołanie rekurencyjne przebiega nieprawidłowo. Zrezygnuj z metody try w ogóle, lub zastąp ją metodą try -> catch, a zwalnianie uchwytu (InternetCloseHandle(hFind)) wstaw na końcu funkcji, gdyż jeżeli uchwyt zostanie zwolniony po wykonaniu metody try, to już go nie ma, ponieważ zdefiniowałeś go jako globalny, zupełnie niepotrzebnie, gdyż może być definiowany lokalnie, czyli wewnątrz funkcji.

Nie chce mi się przepisywać Twojego projektu, więc może zamieścisz go w załączniku, wtedy go skompiluje i sprawdzę.

Jeżeli zdecydujesz się udostępnić projekt to przed spakowaniem usuń z niego pliki tymczasowe.

Plik do usuwania plików tymczasowych, wypakować do katalogu projektu i tam uruchomić.
Nie masz wystarczających uprawnień, aby zobaczyć pliki załączone do tego postu.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4728
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 444
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: Listowanie plików/katalogów z FTP - wininet

Nowy postprzez polymorphism » czwartek, 24 grudnia 2009, 16:16

[...] ponieważ zdefiniowałeś go jako globalny, zupełnie niepotrzebnie, gdyż może być definiowany lokalnie, czyli wewnątrz funkcji.

Nie tyle może być, co musi być, jeśli ta funkcja ma być wywoływana rekurencyjnie.

____
p.s. następny dowód na to, że zmienne globalne to zło. Unikać ich na ile to możliwe...
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2187
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 204
System operacyjny: Windows 7 Pro
Windows 8.1
Linux Mint 19
Kompilator: Visual Studio 2015 Community
CodeLite (MinGW)
MSYS2 (MinGW, clang)
g++
Gadu Gadu: 0
    NieznanyNieznana

Re: Listowanie plików/katalogów z FTP - wininet

Nowy postprzez mckri » czwartek, 24 grudnia 2009, 16:59

Ok, ok, faktycznie bez sensu był globalnie zadeklarowany hFind.
Troche poprawiłem, jednak kłopot jest teraz tego typu, że funkcja listuje pliki z pierwszego, najbardziej 'zagłebionego' podkatalogu oraz z katalogu 'startowego' i zatrzymuje swoje działanie. Nie wyszukuje innych podkatalogów i plików.
Przesyłam załącznik w wersji 2007.
Nie masz wystarczających uprawnień, aby zobaczyć pliki załączone do tego postu.
Avatar użytkownika
mckri
Intelektryk
Intelektryk
 
Posty: 160
Dołączył(a): piątek, 15 sierpnia 2008, 13:48
Podziękował : 10
Otrzymał podziękowań: 2
System operacyjny: Windows Vista SP2
Kompilator: BCB 5/2007/2009
    NieznanyNieznana

Re: Listowanie plików/katalogów z FTP - wininet

Nowy postprzez polymorphism » czwartek, 24 grudnia 2009, 17:56

No a jak inaczej ma robić, jeśli w kodzie masz takie cudo:
Kod: Zaznacz cały
do
{
   if((w32fd.dwFileAttributes==FILE_ATTRIBUTE_DIRECTORY) & ...
   {
      InternetCloseHandle(hFind); //<--- !!!
      ...
}
while(InternetFindNextFile(hFind, &w32fd));


Pierwsze znalezienie katalogu i pętla kończy działanie.



Kod: Zaznacz cały
if((w32fd.dwFileAttributes==FILE_ATTRIBUTE_DIRECTORY) & [...]
if(w32fd.dwFileAttributes!=FILE_ATTRIBUTE_DIRECTORY) [...]

Te warunki są złe. Wartość dwFileAttributes może być sumą (OR) wielu wartości FILE_ATTRIBUTE_.

Wiesz jaka jest różnica między & a &&?



Kod: Zaznacz cały
((String)w32fd.cFileName!=".") & ((String)w32fd.cFileName!="..")

Do porównywania c-stringów masz funkcję strcmp.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2187
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 204
System operacyjny: Windows 7 Pro
Windows 8.1
Linux Mint 19
Kompilator: Visual Studio 2015 Community
CodeLite (MinGW)
MSYS2 (MinGW, clang)
g++
Gadu Gadu: 0
    NieznanyNieznana

Re: Listowanie plików/katalogów z FTP - wininet

Nowy postprzez Cyfrowy Baron » czwartek, 24 grudnia 2009, 20:06

Powinno być:

Kod: Zaznacz cały
if( ((w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0)
      & strcmp(w32fd.cFileName, " .") > 0
      & strcmp(w32fd.cFileName, "..") > 0)
{
  ListujFtp(Lista, Dir + (String)w32fd.cFileName + "/");
  Lista->Items->Add("       -> [DIR] "+(String)w32fd.cFileName);    //tutaj listuje katalogi
  Application->ProcessMessages();
}


Po poprawkach to wciąż nie działa prawidłowo:

Kod: Zaznacz cały
//----------------------------------------------------------------------------
void __fastcall ListujFtp(TListBox *Lista, String Dir)  //listowanie plików/katalogów
{
  WIN32_FIND_DATA w32fd;
  HINTERNET hFind;

  if (hConnect != 0)
  {
       hFind = FtpFindFirstFile(hConnect, "*.*", &w32fd, 0, 0);   //INTERNET_FLAG_RELOAD lub INTERNET_FLAG_NO_CACHE_WRITE, szczegóły na TechNet
       if(hFind != 0)
       {
         do
         {
           if( ((w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0)
              & strcmp(w32fd.cFileName, " .") > 0
              & strcmp(w32fd.cFileName, "..") > 0)
           {
              ListujFtp(Lista, Dir + (String)w32fd.cFileName + "/");
              Lista->Items->Add("       -> [DIR] "+(String)w32fd.cFileName);    //tutaj listuje katalogi
                  Application->ProcessMessages();
           }
              else
              {
             Lista->Items->Add((String)w32fd.cFileName);    //tutaj listuje pliki
                 Application->ProcessMessages();
              }
         }
         while(InternetFindNextFile(hFind, &w32fd));
            InternetCloseHandle(hFind);
          }

  }
  else
  {
   ShowMessage("Brak połączenia z hostem!");
  }
}
//---------------------------------------------------------------------------


Problem w tym, że wyszukiwanie działa tylko w katalogu zdalnym: FtpFindFirstFile(hConnect, "*.*", &w32fd, 0, 0);
Jeżeli dam: FtpFindFirstFile(hConnect, (Dir + "*.*").c_str(), &w32fd, 0, 0); - nie działa
tak też nie działa: FtpFindFirstFile(hConnect, (Dir + "*").c_str(), &w32fd, 0, 0);

a tak musi być, żeby wyszukiwało w podkatalogach, bez tego ani rusz.

Problem w tym, że przy zapisie Dir + "*.*", np: Katalog_zdalny/*.* nie wyliczy żadnych katalogów, ale przy zapisie /*.* wyszuka wszystkie pliki i katalogi w katalogu zdalnym.

Nie mam pomysłu. Coś mi umyka.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4728
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 444
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: Listowanie plików/katalogów z FTP - wininet

Nowy postprzez Cyfrowy Baron » czwartek, 24 grudnia 2009, 20:21

Jeżeli zamiast nazwy katalogu zdalnego podam */ to wyszukuje pliki w podkatalogach, ale wciąż nie działa jak trzeba.

Za ten post autor Cyfrowy Baron otrzymał podziękowanie od:
mckri
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4728
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 444
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: Listowanie plików/katalogów z FTP - wininet

Nowy postprzez mckri » czwartek, 24 grudnia 2009, 21:36

Dzieki za poswięcenie.
Bedę szukał w necie dalej, ale jakos mało informacji w tym temacie.
Avatar użytkownika
mckri
Intelektryk
Intelektryk
 
Posty: 160
Dołączył(a): piątek, 15 sierpnia 2008, 13:48
Podziękował : 10
Otrzymał podziękowań: 2
System operacyjny: Windows Vista SP2
Kompilator: BCB 5/2007/2009
    NieznanyNieznana

Re: Listowanie plików/katalogów z FTP - wininet

Nowy postprzez polymorphism » piątek, 25 grudnia 2009, 11:41

Panowie, trzeba czytać dokładnie dokumentację:

    FtpFindFirstFile is similar to the FindFirstFile function. Note, however, that only one FtpFindFirstFile can occur at a time within a given FTP session. The enumerations, therefore, are correlated with the FTP session handle. This is because the FTP protocol allows only a single directory enumeration per session.

Czyli nie można zagnieżdżać enumeracji plików w jednej sesji. Rozwiązania są dwa:

  • tworzyć nową sesję dla każdego podkatalogu (ta opcja jest najprostsza w realizacji, choć nie wiem czy to przejdzie, trzeba spróbować).
  • wylistować zawartość katalogu, zamknąć uchwyt z FtpFindFirstFile, następnie zrobić to samo dla znalezionych podkatalogów.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2187
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 204
System operacyjny: Windows 7 Pro
Windows 8.1
Linux Mint 19
Kompilator: Visual Studio 2015 Community
CodeLite (MinGW)
MSYS2 (MinGW, clang)
g++
Gadu Gadu: 0
    NieznanyNieznana

Re: Listowanie plików/katalogów z FTP - wininet

Nowy postprzez polymorphism » piątek, 25 grudnia 2009, 13:27

OK, pierwsze rozwiązanie nie działa, w każdym razie u mnie. Pozostaje więc drugie:
Kod: Zaznacz cały
struct ftp_item
{
   bool is_dir;
   string name;

   ftp_item(const string &n,bool dir = false)
      :is_dir(dir),name(n) {}
};

typedef list<ftp_item> ftp_file_list_t;

bool ftpGetFullList(HINTERNET hSession,const string &dir_path,ftp_file_list_t &file_list,ftp_file_list_t::iterator it_0)
{
   WIN32_FIND_DATA w32fd;
   string tmp_path = dir_path + '/';
   ftp_file_list_t::iterator it_1 = file_list.end();   
   ftp_file_list_t::iterator it_2;   

   HINTERNET hFind = FtpFindFirstFile(hSession, (tmp_path + "*.*").c_str(), &w32fd, 0, 0);
   if(!hFind)return false;

   do
   {
      bool dir = (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
      if(dir && (strcmp(w32fd.cFileName, ".") == 0 || strcmp(w32fd.cFileName, "..") == 0))continue;
      it_2 = file_list.insert(it_0,ftp_item(tmp_path + w32fd.cFileName,dir));
      if(it_1 == file_list.end())it_1 = it_2;
   }
   while(InternetFindNextFile(hFind, &w32fd));

   InternetCloseHandle(hFind);

   for(ftp_file_list_t::iterator i = it_1; i != it_0;)
   {
      if(!i->is_dir){ ++i; continue; }
      ftp_file_list_t::iterator j = i;
      if(!ftpGetFullList(hSession,i->name,file_list,++j))return false;
      i = j;
   }

   return true;
}

Użycie:
Kod: Zaznacz cały
ftp_file_list_t   file_list;

...
   
ftpGetFullList(hSession,"",file_list,file_list.end());

...

for(ftp_file_list_t::iterator i = file_list.begin(); i != file_list.end(); ++i)
      cout << i->name << ' ' << (i->is_dir ? "[DIR]" : "") << '\n';
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2187
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 204
System operacyjny: Windows 7 Pro
Windows 8.1
Linux Mint 19
Kompilator: Visual Studio 2015 Community
CodeLite (MinGW)
MSYS2 (MinGW, clang)
g++
Gadu Gadu: 0
    NieznanyNieznana

Re: Listowanie plików/katalogów z FTP - wininet

Nowy postprzez Cyfrowy Baron » piątek, 25 grudnia 2009, 18:08

Czyli nie można zagnieżdżać enumeracji plików w jednej sesji


Można, jak napisałem wcześniej, z wykorzystaniem rekurencji można wyliczać pliki w podkatalogu, katalogu zdalnego, czyli wyliczone zostaną pliki nie tylko w katalogu zdalnym (*/*.*) ale również np. w jego podkatalogu images (*/images/*.*).
Jeżeli jako katalog zdalny podam */ to nawet bez wywołania rekurencyjnego zostaną wyliczone wszystkie pliki, katalogi i podkatalogi w katalogu zdalnym. Problem stanowi połączenie konkretnych plików z właściwymi katalogami, gdyż najpierw są wyliczane pliki, a dopiero potem katalogi.

Do wyliczenia całej zawartości katalogu zdalnego wystarczy taki kod:

Kod: Zaznacz cały
//----------------------------------------------------------------------------
void __fastcall ListujFtp(TListBox *Lista)
{
  WIN32_FIND_DATA w32fd;
  HINTERNET hFind;
  if (hConnect != 0)
  {
       hFind = FtpFindFirstFile(hConnect, "*/*", &w32fd, INTERNET_FLAG_RELOAD, 0);   
       if(hFind != 0)
       {
         do
         {
           if( ((w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0)
                              && w32fd.cFileName != "."
                              && w32fd.cFileName != "..")
           {
                            Lista->Items->Add("       -> [DIR] " +(String)w32fd.cFileName);
                            Application->ProcessMessages();
           }
                         else
                         {
                           Lista->Items->Add((String)w32fd.cFileName);
                           Application->ProcessMessages();
                         }
         }
         while(InternetFindNextFile(hFind, &w32fd));
          }
  }
  else
  {
   ShowMessage("Brak połączenia z hostem!");
  }
  InternetCloseHandle(hFind);
}
//---------------------------------------------------------------------------


Jak widać rekurencja jest zbędna.

Sugerując się tą wypowiedzią:
wylistować zawartość katalogu, zamknąć uchwyt z FtpFindFirstFile, następnie zrobić to samo dla znalezionych podkatalogów.


Opracowałem taki kod:

Kod: Zaznacz cały
//---------------------------------------------------------------------------
enum TftpType {ftpDir, ftpFile};
void __fastcall ListujFtp(TStrings *Lista, String Dir, TftpType Typ)
{
  WIN32_FIND_DATA w32fd;
  HINTERNET hFind;

  if (hConnect != 0)
  {
   FtpSetCurrentDirectory(hConnect, Dir.c_str());

   hFind = FtpFindFirstFile(hConnect, "*/*.*", &w32fd, INTERNET_FLAG_RELOAD, 0);

   if(hFind != 0)
   {
     do
     {
      if( ((w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0)
         && w32fd.cFileName != "."
         && w32fd.cFileName != ".."
         && Typ == ftpDir)
      {
        Lista->Add("[DIR] " +(String)w32fd.cFileName);
        Application->ProcessMessages();
      }
      if(Typ == ftpFile)
      {
       String fileName = (String)w32fd.cFileName;
       fileName = fileName.Delete(fileName.Length() - 1, 1);
        Lista->Add(Dir + "\\" + fileName);
        Application->ProcessMessages();
      }
     }
     while(InternetFindNextFile(hFind, &w32fd));
   }
  }
  else
  {
   ShowMessage("Brak połączenia z hostem!");
  }
  InternetCloseHandle(hFind);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
   ListBox1->Items->Clear();
   TStrings *dirList = new TStringList();
   ListujFtp(dirList, Edit4->Text, ftpDir);

   ListBox1->Items->AddStrings(dirList);

   for(int i = 0; i < dirList->Count; i++)
   {
    String Dir = dirList->Strings[i].Delete(1, 6); //usuwa [DIR]
    ListujFtp(ListBox1->Items, Dir, ftpFile);
   }

   delete dirList;
   ShowMessage("Koniec");
}
//---------------------------------------------------------------------------


Wymaga to jeszcze dopracowania, ale mi się już nie chce. Wyliczenie wszystkich plików na koncie ftp może zająć sporo czasu.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4728
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 444
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: Listowanie plików/katalogów z FTP - wininet

Nowy postprzez polymorphism » piątek, 25 grudnia 2009, 20:10

Można

No nie można. Jakby można było, to kod by działał, a w dokumentacji napisaliby co innego.

Jeżeli jako katalog zdalny podam */ to nawet bez wywołania rekurencyjnego zostaną wyliczone wszystkie pliki

Być może jest to zależne od serwera, ale u mnie nie listuje plików (ftp://ftp.vectranet.pl). Zapisy '*/', '*/*' i '*/*.*' w ogóle nie przechodzą, funkcja zwraca błąd ERROR_NO_MORE_FILES.

Pewniejszy będzie jednak sposób, który podałem.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2187
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 204
System operacyjny: Windows 7 Pro
Windows 8.1
Linux Mint 19
Kompilator: Visual Studio 2015 Community
CodeLite (MinGW)
MSYS2 (MinGW, clang)
g++
Gadu Gadu: 0
    NieznanyNieznana

Re: Listowanie plików/katalogów z FTP - wininet

Nowy postprzez Cyfrowy Baron » piątek, 25 grudnia 2009, 20:24

No nie można.


Możemy się tak sprzeczać w nieskończoność, gdyż u mnie można i u mnie to działa tak jak to opisałem. To co napisali najwyraźniej nie odnosi się do hosta ftp.republika.pl, tylko że to nic nie daje gdyż dokładnie taki sam efekt uzyskuję w przypadku jednorazowego wywołania funkcj, czyli bez rekurencji, wylicza mi wszystkie katalogi, podkatalogi, pliki w katalogu zdalnym i w podkatalogach

Jeżeli się dobrze przyjrzysz temu co napisałem, to zauważysz funkcję: FtpSetCurrentDirectory(hConnect, Dir.c_str());, która to służy do zmiany katalogów i wyliczaniu plików w kolejnych katalogach. W połączeniu z pętlą można wyliczyć wszystkie katalogi, podkatalogi, pliki i pliki w podkatalogach i powiązać pliki z podkatalogami do których przynależą. Nie dodałem tylko funkcji łączącej podkatalogi z katalogiem nadrzędnym, gdyż funkcja wyliczająca katalogi w katalogu zdalnym wylicza mi wszystkie katalogi i podkatalogi i nie mogę tego rozdzielić. Jeżeli zadam do wyszukiwania katalog zdalny: katalog_zdalny/*.* to nic nie zostanie wyliczone. U mnie działa tylko */katalog/*.*
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4728
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 444
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Następna strona

  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Aplikacje sieciowe

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 1 gość

cron