[IndyFTP] Sprawdzanie czy istnieje plik

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

[IndyFTP] Sprawdzanie czy istnieje plik

Nowy postprzez Michalos » niedziela, 26 października 2008, 16:46

Witam!

Czy istnieje odpowiednik funkcji FileExists w tym komponencie? Czy może da się wykorzystać tą funkcję do sprawdzania czy istnieje plik na FTP . Z góry dzięki za pomoc.

Pozdrawiam!
Avatar użytkownika
Michalos
Bladawiec
Bladawiec
 
Posty: 35
Dołączył(a): niedziela, 19 października 2008, 11:45
PodziÄ™kowaÅ‚ : 1
OtrzymaÅ‚ podziÄ™kowaÅ„: 0
    NieznanyNieznana

Re: [IndyFTP] Sprawdzanie czy istnieje plik

Nowy postprzez Cyfrowy Baron » poniedziaÅ‚ek, 27 października 2008, 14:04

Nie słyszałem o podobnej, gotowej funkcji do sprawdzania istnienia pliku na koncie FTP. Można to jednak sprawdzić wykorzystując komponent IdFTP, zgodnie z opisem w serwisie Cyfrowy Baron w dziale: sieć - internet -> porada: ściąganie i wysyłanie plików przez protokół FTP. W podanej poradzie pokazany jest sposób łączenia z serwerem, co do sprawdzania czy plik istnieje, to trzeba wykorzystać funkcję List komponentu IdFTP:

Kod: Zaznacz cały
void __fastcall TForm1::Button3Click(TObject *Sender)
{
bool test = true;
try{ IdFTP1->List(NULL, "indeks.html", false); }catch(...){test = false;}

if(test == true)
  ShowMessage("Znaleziono plik");
else
  ShowMessage("Brak pliku");
}
//---------------------------------------------------------------------------


W przedstawionym kodzie sprawdzany będzie plik w katalogu głównym konta, jeżeli chcemy sprawdzić czy plik znajduje się w jakimś katalogu, to trzeba najpierw przejść do tegoż katalogu, a dopiero potem sprawdzać istnienie pliku, służy do tego funkcja ChangeDir:

Kod: Zaznacz cały
void __fastcall TForm1::Button3Click(TObject *Sender)
{
IdFTP1->ChangeDir("files"); // przejście z katalogu głównego do podkatalogu files
bool test = true;
try{ IdFTP1->List(NULL, "gdiplus.rar", false); }catch(...){test = false;}

if(test == true)
  ShowMessage("Znaleziono plik");
else
  ShowMessage("Brak pliku");
}
//---------------------------------------------------------------------------


Jeżeli w podkatalogu znajduje się jeszcze jeden katalog, to trzeba przechodzić kolejno do tych katalogów:

Kod: Zaznacz cały
void __fastcall TForm1::Button3Click(TObject *Sender)
{
IdFTP1->ChangeDir("files"); // przejście z katalogu głównego do podkatalogu files
IdFTP1->ChangeDir("grafika"); // przejÅ›cie z  podkatalogu files do podkatalogu grafika
bool test = true;
try{ IdFTP1->List(NULL, "image.bmp", false); }catch(...){test = false;}

if(test == true)
  ShowMessage("Znaleziono plik");
else
  ShowMessage("Brak pliku");
}
//---------------------------------------------------------------------------


Żeby cofnąć się do katalogu o jeden stopień wcześniej trzeba skorzystać z funkcji ChangeDirUp:

Kod: Zaznacz cały
void __fastcall TForm1::Button3Click(TObject *Sender)
{
IdFTP1->ChangeDir("files"); // przejście z katalogu głównego do podkatalogu files
IdFTP1->ChangeDirUp(); // cofniecie się o jeden katalog wstecz, czyli tutaj do katalogu głównego
bool test = true;
try{ IdFTP1->List(NULL, "gdiplus.rar", false); }catch(...){test = false;}

if(test == true)
  ShowMessage("Znaleziono plik");
else
  ShowMessage("Brak pliku");
}
//---------------------------------------------------------------------------




Funkcja List służy do wyliczania plików w katalogu. Pobiera trzy argumenty, pierwszy argument to wskaźnik na obiekt typu TStrings, czyli na listę, drugi argument określa maskę wyszukiwania plików, czyli możemy tutaj określić czy chcemy wyszukiwać wszystkie pliki, tylko pliki, konkretny plik itd.
  • Jeżeli podamy jako wartość pustÄ… ("") to wyliczone zostanÄ… wszystkie pliki i katalogi w przeszukiwanym katalogu.
  • Jeżeli podamy jako wartość gwiazdkÄ™ ("*") to wyliczone zostanÄ… wszystkie pliki i katalogi w przeszukiwanym katalogu oraz pliki we wszystkich katalogach
  • Jeżeli podamy jako wartość dwie gwiazdki rozdzielone kropkÄ… ("*.*") to wyliczone zostanÄ… tylko wszystkie pliki przeszukiwanym katalogu.
  • Jeżeli podamy jako wartość dwie gwiazdki kropkÄ™ i rozszerzenie pliku ("*.html") to wyliczone zostanÄ… tylko pliki z zadanym rozszerzeniem przeszukiwanym katalogu.
  • Jeżeli podamy jako wartość nazwÄ™ pliku z rozszerzeniem ("index.html") to wyliczony zostanie tylko plik o takiej nazwie w przeszukiwanym katalogu.

Trzeci argument określa typ wyliczania zawartości folderu false - bez szczegółow, true - ze szczegółami:

Kod: Zaznacz cały
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
IdFTP1->List(ListBox1->Items, "*.html", true);
}
//---------------------------------------------------------------------------
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
PodziÄ™kowaÅ‚ : 12
OtrzymaÅ‚ podziÄ™kowaÅ„: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: [IndyFTP] Sprawdzanie czy istnieje plik

Nowy postprzez Witold » poniedziaÅ‚ek, 27 października 2008, 16:36

Cyfrowy Baron napisał(a):IdFTP1->List(NULL, "indeks.html", false); }catch(...){test = false;}


Pod BCB6/Indy8 IdFTP1->List(NULL,…) powoduje wyjątek:
Access violation at addres.... Read of adress 000000000.
Wychodzi że nie można użyć NULL’a (BCB6/Indy8).
Avatar użytkownika
Witold
Konstrukcjonista
Konstrukcjonista
 
Posty: 223
Dołączył(a): piątek, 29 sierpnia 2008, 10:53
PodziÄ™kowaÅ‚ : 1
OtrzymaÅ‚ podziÄ™kowaÅ„: 14
Kompilator: bcb6, Turbo C++ Explorer
    NieznanyNieznana

Re: [IndyFTP] Sprawdzanie czy istnieje plik

Nowy postprzez Cyfrowy Baron » poniedziaÅ‚ek, 27 października 2008, 17:44

Prawdopodobnie jest to związane z błędami środowiska Borland C++ Builder 6. Na storona firmy Borland w FAQ można znaleźć informację o możliwych błędach przy korzystaniu z komponentów stworzonych w Delphi, a w szczególnośći przy komponentach INDY. Błędy naprawia patche 2 dla tego środowiska.
Niemniej jednak, jeżeli nie można użyć NULL, należy podać jako wskaźnik odwołąnie do obiektu typu TStrings:

Kod: Zaznacz cały
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
TStrings *Lista = new TStringList;
bool test = true;
try{ IdFTP1->List(Lista, "index.html", false); }catch(...){test = false;}
delete Lista;

if(test == true)
  ShowMessage("Znaleziono plik");
else
  ShowMessage("Brak pliku");
}
//---------------------------------------------------------------------------
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
PodziÄ™kowaÅ‚ : 12
OtrzymaÅ‚ podziÄ™kowaÅ„: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: [IndyFTP] Sprawdzanie czy istnieje plik

Nowy postprzez Michalos » poniedziaÅ‚ek, 27 października 2008, 18:41

Zrobiłem takie coś
Kod: Zaznacz cały
bool fileexist(TIdFTP *IdFTP1, String fn)
{
   int ilosc = Lista->Count;
   int i=1;
   for (i; i < ilosc; i++) {
   TStringList *l= new TStringList;
   IdFTP1->List(l,fn,false);
   int exist = l->Count;
   return exist;
   }
}


a następnie
Kod: Zaznacz cały
if(fileexist(IdFTP1,sciezka)==0)
{
IdFTP1->Put(...); // jesli go nie ma na FTP to wysyla
}



Bo celem mojego programiku jest aktualizowanie bazy danych, tzn porównywanie zawartości zamówień na dysku i zawartością zamówień na FTP i w zależności od tego gdzie brakuje to wysyła/pobiera. Ale jest jeszcze jeden przypadek nazwa może być ta sama, ale plik został edytowany i zapisany pod ta nazwa i oczywiste jest to żeby była aktualna baza - w tym wypadku użyję chyba porównywania rozmiarów plików jest funkcja Size w komponencie IdFTP i jest też jakaś funkcja co zwraca rozmiar pliku na dysku. Nie jestem pewien czy to wystarczy :P Tak to najlepiej będzie wyciągnąć datę edycji pliku, przy wyświetlaniu listy plików na FTP, za pomocą f-cji List() trzeci argument to true/false true to szczegóły dotyczące plików ( atrybuty pliku kto moze korzystać itd. jest też data z godzina edycji - jak tą informacje wyciągnąć ? Może ktoś poradzić? Tu chyba trzeba wykorzystać operacje na Stringach? Chyba że jest jakaś gotowa funkcja ;)

Pozdrawiam
Avatar użytkownika
Michalos
Bladawiec
Bladawiec
 
Posty: 35
Dołączył(a): niedziela, 19 października 2008, 11:45
PodziÄ™kowaÅ‚ : 1
OtrzymaÅ‚ podziÄ™kowaÅ„: 0
    NieznanyNieznana

Re: [IndyFTP] Sprawdzanie czy istnieje plik

Nowy postprzez Cyfrowy Baron » poniedziaÅ‚ek, 27 października 2008, 22:04

W celu wyciągnięcia daty, należy poddać tekst parsowaniu. Nie jestem jednak w stanie podać przykładu dla Twoich potrzeb, gdyż przytoczony przez Ciebie przykładowy kod z pewnością działa, lecz jest pozbawiony sensu.

Przeanalizujmy go:

Przekazujesz do funkcji fileexist zmienną fn, potem w każdym obiegu pętli for wywołujesz funkcję List z tą samą wartością zmiennej fn, a dokładnie w każdym obiegu pętli funkcja List wykonuje identyczne działanie, czyli za każdym razem wykonuje dokładnie to samo zadanie. Nawet wartość zmiennej exist w każdym obiegu pętli jest ta sama, gdyż funkcja List wciąż pobiera te same dane z tej samej lokalizacji, gdyż nic się nie zmienia, więc jaki sens ma tutaj użycie pętli?.
Sama funkcja fileexist jest źle skonstruowana, jest to funkcja zwracająca wartość typu BOLEAN (bool), a Ty tymczasem zwracasz jej wartość typu INTEGER (int):

int exist = l->Count;
return exist;

Funkcja fileexists zwraca wartość wewnątrz pętli, a jak wiadomo funkcja return przerywa wszelkie działanie, a to oznacza, że działanie pętli zostanie przerwane już w pierwszym obiegu, więc po raz kolejny pytam jaki sens ma tutaj użycie pętli?.

Funkcja fileexists oczekuje, że zostanie zwrócona jakaś wartość, i jest zwracana w pętli, jednak prawidłowo powinno się to odbywać poza pętlą.

Kolejna sprawa:

Kod: Zaznacz cały
if(fileexist(IdFTP1,sciezka)==0)
{
IdFTP1->Put(...); // jesli go nie ma na FTP to wysyla
}


Niby poprawny, ale jak juz wspomniałem funkcja fileexists oczekuje wartości typu bool a Ty tymczasem porównujesz ja z wartością INTEGER, w tym konkretnym przypadku to zadziała, gdyż 0 = false, a wartość 1 = true, ale prawidłowy zapis powinien wyglądać tak:

Kod: Zaznacz cały
if(fileexist(IdFTP1,sciezka) == false)
{
IdFTP1->Put(...); // jesli go nie ma na FTP to wysyla
}


lub tak:

Kod: Zaznacz cały
if( !fileexist(IdFTP1,sciezka) )
{
IdFTP1->Put(...); // jesli go nie ma na FTP to wysyla
}


Zastanawiająca jest ta nazwa zmiennej sciezka, sugeruje to, że przekazujesz do funkcji List jakąś ścieżkę to pliku, podczas gdy ta funkcja, żadnych ścieżek nie przyjmuje, jedyne sensowne wartości to: *; *.*; *.rozszerzenie; nazwa_pliku.*; nazwa_pliku.rozszerzenie

Przemyśl swój kod i napisz go tak, żeby to maiło sens, a wtedy pokaże Tobie jak wyciągnąć tą datę i czas. Dopóki nie rozumiesz zasady działania własnego kodu, to nie ma sensu go bardziej komplikować, gdyż zupełnie się pogubisz i zaczniesz zadawać masę bezsensownych pytań.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
PodziÄ™kowaÅ‚ : 12
OtrzymaÅ‚ podziÄ™kowaÅ„: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: [IndyFTP] Sprawdzanie czy istnieje plik

Nowy postprzez Michalos » niedziela, 2 listopada 2008, 00:47

Witam, przepraszam że tak długo nie odpisywałem :)

Na wstępie chciałbym podziękować Baronowi za wyczerpującą odpowiedź. Rzeczywiście pogubiłem się w tym kodzie. Trochę posiedziałem przy tym i przebudowałem całkowicie program. Napisałem jak na razie 3 funkcje do pobierania z FTP (3 bo potrzebne do 3 katalogów). Oto one:

Funkcja zlecienia() - odpowiada za porównanie zawartości katalogu //Zlecenia na FTP z katalogiem na dysku.
Kod: Zaznacz cały
void zlecenia()
{
IdFTP1->ChangeDir("Zlecenia");
IdFTP1->List(ftp, "*.*", false);
int ilosc = ftp->Count;
int i=2;
   for (i; i < ilosc; i++)
   {
      String nazwa_pliku = ftp->Strings[i];
      String sciezka = "D:\\Baza\\Zlecenia\\" + nazwa_pliku;
      if(!FileExists(sciezka))
      {
      IdFTP1->Get(nazwa_pliku,sciezka,true,false);
      }
   }
   for (i=0; i < ilosc; i++)
   {
      ftp->Delete(i);
   }
}

zmienna i ma wartość 2, ponieważ po wyświetleniu listy plików folderu Zlecenia na górze znajdują się dwie linie z kropkami, 1 linia z jedna kropka, 2 linia z dwoma kropkami. Funkcję Delete(i) pewnie można umieścić w tej pierwszej pętli - nie wiem sam czemu tak zrobiłem, bo chyba mogę ją tam umieścić na samym końcu ? Usuwam, bo korzystam z jednego obiektu TStringList, który przydaję mi się później ;)

funkcja PDF_K() - analogiczna do poprzedniej
Kod: Zaznacz cały
void PDF_K()
{
   IdFTP1->ChangeDirUp();
   IdFTP1->ChangeDir("PDF_K");
   IdFTP1->List(ftp, "*.*", false);
   int ilosc = ftp->Count;
   int i=2;
   for (i; i < ilosc; i++) {
      String nazwa_pliku = ftp->Strings[i];
      String sciezka = "D:\\Baza\\PDF_K\\" + nazwa_pliku;
      if(!FileExists(sciezka)){
      IdFTP1->Get(nazwa_pliku,sciezka,true,false);
      }
   }
   for (i=0; i < ilosc; i++) {
      ftp->Delete(i);
   }
}


oraz funkcja PDF_V() - podobna jak poprzednie

Kod: Zaznacz cały
void PDF_V()
{
   IdFTP1->ChangeDirUp();
   IdFTP1->ChangeDir("PDF_V");
   IdFTP1->List(ftp, "*.*", false);
   int ilosc = ftp->Count;
   int i=2;
   for (i; i < ilosc; i++) {
      String nazwa_pliku = ftp->Strings[i];
      String sciezka = "D:\\Baza\\PDF_V\\" + nazwa_pliku;
      if(!FileExists(sciezka)){
      IdFTP1->Get(nazwa_pliku,sciezka,true,false);
      }
   }
   for (i=0; i < ilosc; i++) {
      ftp->Delete(i);
   }
}


Następnie umieściłem te funkcje w zdarzeniu przycisku:
Kod: Zaznacz cały
void __fastcall TForm1::Button4Click(TObject *Sender)
{
zlecenia();
PDF_V();
PDF_K();
}


Przy kompilacji programu nie ma błędu, natomiast jeśli użyję tego zdarzenia wyskakuje błąd, którego nie mogę zrozumieć
Access violation at address 007302BC in module 'IndyProtocols100.bpl'. Read of address 00000000'. Process Project1.exe (3664)


Stworzyłem też funkcję wysyłająca pliki jeśli go nie ma na FTP, ale ona też nie działa - zero reakcji, na pewno coś poknociłem :P
Oto ona:
Kod: Zaznacz cały
void zlecenia_ftp()
{
   FindDir(local, "d:\\Baza\\Zlecenia", "");
   int ilosc= local->Count;
   int i=0;
   if(ilosc!=0)
   {
   for (i; i < ilosc; i++)
   {
      String nazwa_pliku = local->Strings[i];
      String sciezka_ftp = "\\Zlecenia" + nazwa_pliku;
      String sciezka_local = "D:\\Baza\\Zlecenia\\" + nazwa_pliku;
      IdFTP1->ChangeDirUp();
      IdFTP1->ChangeDir("Zlecenia");
      IdFTP1->List(ftp,nazwa_pliku,false);
      int exist = ftp->Count;
      if(exist!=1)
         {
         IdFTP1->Put(sciezka_local,sciezka_ftp,true);
         }
   }
   }
}


Zmodyfikowałem nieco Twoją funkcję FindDir

Kod: Zaznacz cały
void FindDir(TStringList *local, String Dir, String typ)
{
TSearchRec sr;

  if(FindFirst(Dir + "*.*", faAnyFile, sr) == 0)
    {
     do{
       if(((sr.Attr & faDirectory) > 0) && (sr.Name != ".") && (sr.Name != ".."))
        {
         FindDir(local, Dir + sr.Name + "\\", typ);
        }
         if((sr.Attr & faDirectory) == 0){
          if(typ.IsEmpty())
           local->Add(sr.Name);

          else if(ExtractFileExt(sr.Name).SubString(2, 5) == typ)
           local->Add(sr.Name);
                                 }
      }
      while(FindNext(sr) == 0);
      FindClose(sr);
    }
}

Umieściłem listę w obiekcie TStringList i zrobiłem żeby dodawał jedynie nazwę pliku - po to by się odwoływać do pliku a nie całej ścieżki.
I ta funkcja praktycznie w ogóle nie działa pewnie jest zero elementów :P Źle przerobiłem tą funkcję. Zwracam się do Was o pomoc . Ja już się pogubiłem ... Proszę o jakieś wskazówki gdzie popełniłem błąd ;)

Pozdrawiam serdecznie i czekam na odpowiedź :)
Avatar użytkownika
Michalos
Bladawiec
Bladawiec
 
Posty: 35
Dołączył(a): niedziela, 19 października 2008, 11:45
PodziÄ™kowaÅ‚ : 1
OtrzymaÅ‚ podziÄ™kowaÅ„: 0
    NieznanyNieznana

Re: [IndyFTP] Sprawdzanie czy istnieje plik

Nowy postprzez Cyfrowy Baron » niedziela, 2 listopada 2008, 09:45

Znów wszystko popieprzyłeś. masa błędów...!



Kod pierwszy:
Co to za bzdura:

int i=2;
for (i; i < ilosc; i++)
{

powinno być:

int i;
for (i = 2; i < ilosc; i++)
{



Piszesz, że funkcja "Funkcja zlecienia() - odpowiada za porównanie zawartości katalogu //Zlecenia na FTP z katalogiem na dysku.", a ja tym czasem widzę po kodzie, ze ta funkcja pobiera pliki z serwera, poza tym druga pętla w tej funkcji:

for (i=0; i < ilosc; i++)
{
ftp->Delete(i);
}

czyści listę.
W drugiej i trzeciej funkcji te same błędy implementacyjne.



Wywołanie funkcji w jednym zdarzeniu po drugim może nie działać prawidłowo dla obiektu IdFTP:

void __fastcall TForm1::Button4Click(TObject *Sender)
{
zlecenia();
PDF_V();
PDF_K();
}

powinien istnieć mechanizm sprawdzający czy pierwsze funkcja już zrealizowała zadanie, jeżeli tak, to program przechodzi do funkcji następnej.



Funkcję FindDir przerobiłeś prawidłowo, ale podając ścieżkę dostępu do przeszukiwanego katalogu trzeba ją zakończyć podwójną kreską ułamkową odwróconą, czyli np. tak:

FindDir(local, "d:\\Baza\\Zlecenia\\", ""); // tutaj zmieniłem: "d:\\Baza\\Zlecenia\\"

Można oczywiście zmodyfikować funkcję tak, żeby sama sprawdzała czy te kreski tam są, jeżeli nie ma to je sama doda, wtedy ta funkcja mogłaby wyglądać tak:
Kod: Zaznacz cały
//---------------------------------------------------------------------------
void FindDir(TStringList *local, String Dir, String typ)
{
Dir = (Dir.SubString(Dir.Length(), 1) != "\\") ? Dir + "\\" : Dir;
TSearchRec sr;

  if(FindFirst(Dir + "*.*", faAnyFile, sr) == 0)
    {
     do{
       if(((sr.Attr & faDirectory) > 0) && (sr.Name != ".") && (sr.Name != ".."))
        {
         FindDir(local, Dir + sr.Name + "\\", typ);
        }
         if((sr.Attr & faDirectory) == 0){
          if(typ.IsEmpty())
           local->Add(sr.Name);

          else if(ExtractFileExt(sr.Name).SubString(2, 5) == typ)
           local->Add(sr.Name);
                                 }
      }
      while(FindNext(sr) == 0);
      FindClose(sr);
    }
}
//---------------------------------------------------------------------------




Pracuj dalej, Twój kod ma wciąż mnóstwo błędów, ale widać, że się uczysz.
Nie twórz wszystkiego od razu, najpierw napisz jedną funkcje i sprawdź czy działa, jeżeli nie to analizuj kod, szukaj błędów, dopiero gdy pierwsza funkcja będzie działać bezbłędnie przejdź do tworzenia drugiej. Gdy już będziesz miał wszystkie działające funkcje nie uruchamiaj ich wszystkich na raz w jednym zdarzeniu, lecz po kolei, a później kombinuj ze wszystkimi na raz.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
PodziÄ™kowaÅ‚ : 12
OtrzymaÅ‚ podziÄ™kowaÅ„: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: [IndyFTP] Sprawdzanie czy istnieje plik

Nowy postprzez Michalos » niedziela, 2 listopada 2008, 10:56

Cyfrowy Baron napisał(a):Kod pierwszy:
Co to za bzdura:

int i=2;
for (i; i < ilosc; i++)
{

powinno być:

int i;
for (i = 2; i < ilosc; i++)
{


Możesz mi wyjaśnić różnicę pomiędzy (w moim przypadku) definicji zmiennej (w Twoim przypadku) najpierw deklaracja a następnie przypisanie do zmiennej wartość 2?
Tak naprawdę można to zrobić w samej funkcji for (definicje).
Kod: Zaznacz cały
for (int i = 2; i < ilosc; i++)


Cyfrowy Baron napisał(a):Piszesz, że funkcja "Funkcja zlecienia() - odpowiada za porównanie zawartości katalogu //Zlecenia na FTP z katalogiem na dysku.", a ja tym czasem widzę po kodzie, ze ta funkcja pobiera pliki z serwera

Fakt, źle się wysłowiłem. Zadaniem tej funkcji jest pobranie listy plików na ftp w katalogu Zlecenia, i następnie sprawdzenie czy wszystkie pliki są na dysku, jeśli któregoś nie ma to go pobiera.

Masz rację z tymi funkcjami w zdarzeniu, ale jak usunąłem pozostałe 2, została tylko jedna zlecenia() to i tak pojawiał się ten sam błąd. Wrzuciłem zawartość funkcji do zdarzenia i o dziwo działa prawidłowo, pobiera jak nie ma pliku, był błąd chyba z usuwaniem elementów tej listy, ponieważ wyskoczył błąd:
Kod: Zaznacz cały
List index of bounds(41)

Czyli odwołanie się do czegoś, czego nie ma - chyba. Po usunięciu tej drugiej pętli działa prawidłowo, Usuwam te wszystkie elementy z listy, ponieważ chciałem w późniejszym czasie skorzystać z tego samego obiektu klasy TStringList. Mam pytanie: Czy jak po raz kolejny wywołam "Listowanie" - funkcję List() z IdFTP to on zamieni te wszystkie elementy ? Czy mogą wystąpić problemy? Jak nie to dobrze, nie będzie potrzeby czyszczenia obiektu.

A co do tego wywołania:
Kod: Zaznacz cały
FindDir(local, "d:\\Baza\\Zlecenia\\", "");

Powstaje błąd
[ILINK32 Error] Error: Unresolved external '__fastcall TForm1::FindDir(Classes::TStringList *, System::AnsiString, System::AnsiString)' referenced from D:\DOCUMENTS AND SETTINGS\ADMINISTRATOR\MOJE DOKUMENTY\RAD STUDIO\PROJECTS\FTP\DEBUG_BUILD\UNIT1.OBJ

Definicja funkcji jest zaraz za includami w pliku Unit1.cpp
Avatar użytkownika
Michalos
Bladawiec
Bladawiec
 
Posty: 35
Dołączył(a): niedziela, 19 października 2008, 11:45
PodziÄ™kowaÅ‚ : 1
OtrzymaÅ‚ podziÄ™kowaÅ„: 0
    NieznanyNieznana

Re: [IndyFTP] Sprawdzanie czy istnieje plik

Nowy postprzez Cyfrowy Baron » niedziela, 2 listopada 2008, 12:51

Zacznę od końca:
Przetestowałem u siebie tą Twoją funkcję FindDir i działa poprawnie, więc prawdopodobnie źle definiujesz obiekt local typu TStringList.
Prawidłowo powinno to wyglądać tak:
Ponieważ z Twojego kodu wynika, że local jest obiektem globalnym, to w pliku nagłówkowym (np. Unit1.h) w sekcji private lub public musisz umieścić deklarację tego obiektu:
Kod: Zaznacz cały
private:
          TStringList *local;


Następnie w pliku źródłowym (np. Unit1.cpp) umieszczasz definicję, najlepiej w konstruktorze klasy:

Kod: Zaznacz cały
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
   : TForm(Owner)
{
local = new TStringList;
}
//---------------------------------------------------------------------------


Obiekt jest gotowy do użycia. U mnie wszystko działa bezbłędnie odnośnie obiektu local i funkcji FindDir, więc niczego więcej nie mogę doradzić.



Co do tego:
int i=2;
for (i; i < ilosc; i++)

można tak zrobić, ale łatwo się pogubić gdy wartość zmiennej jest ustalana poza pętlą w której jest wykorzystywana. To właśnie takie programowanie prowadzi do błędów implementacji w dalszej części kodu, gdy zapomina się co się skąd wzięło. Język C++ ze względu na swoją dużą elastyczność zezwala na takie skróty, ale jest to niedobry zwyczaj.

taki zapis:

int i;
for (i = 2; i < ilosc; i++)

różni się tym od tego:

for (int i = 2; i < ilosc; i++)

różnią się tym, że w pierwszym przypadku możesz użyć tej samej zmiennej w innych pętlach lub do dalszego przetwarzania, podczas gdy w drugim przypadku zdefiniowana zmienna nie istnieje poza pętlą i może być użyta tylko wewnątrz pętli.



Tworzysz funkcje lokalne niepołączone z klasą formularza:

void zlecenia()
{
IdFTP1->ChangeDir("Zlecenia");
IdFTP1->List(ftp, "*.*", false);

w powyższym przykładzie funkcja zlecenia nie jest do niczego przypisana, ale wewnątrz funkcji odwołujesz się do obiektu IdFTP1 przypisanego do klasy formularza, zadziwiające jest dla mnie to, ze ten kod wogóle się kompiluje, u mnie w tej sytuacji kompilator zgłosiłby komunikat, że nie wie czym jest obiekt IdFTP1. Poza tym funkcja nie może tutaj nie zawierać żadnego argumentu, może być pusta, ale w takim przypadku należy jej przekazać argument void:

void zlecenia(void)

Zanim przejdziesz dalej przeczytaj sobie artykuł w serwisie Cyfrowy Baron w dziale teoria -> Funkcje, gdyż nie odróżniasz funkcji lokalnej od globalnej.

Jeżeli decydujesz się stworzyć funkcję globalną nie przypisaną do klasy formularza, to taka funkcja musi znajdować się przed inną funkcją lub zdarzeniem przez które jest wywoływana, no i jeżeli w takiej funkcji odwołujesz się do obiektów przypisanych do formularza to musisz je prawidłowo adresować, jeżeli więc formularz nazywa się np. Form1, to taki kod powinien mieć następującą postać:

Kod: Zaznacz cały
    void zlecenia(void)
    {
      Form1->IdFTP1->ChangeDir("Zlecenia"); // adresowanie na Form1
      Form1->IdFTP1->List(ftp, "*.*", false); // adresowanie na Form1
      int ilosc = Form1->ftp->Count;
      int i;
      for(i = 2; i < ilosc; i++)
       {
          String nazwa_pliku = Form1->ftp->Strings[i];
          String sciezka = "D:\\Baza\\Zlecenia\\" + nazwa_pliku;
          if(!FileExists(sciezka))
          {
           Form1->IdFTP1->Get(nazwa_pliku, sciezka, true, false);
          }
       }
       for (i=0; i < ilosc; i++)
       {
          Form1->ftp->Delete(i);
       }
    }



możesz też utworzyć zmienną globalną (sekcja public pliku nagłówkowego *.h) lub lokalną (sekcja private pliku nagłówkowego), ale przypisaną do klasy formularza. W takiej sytuacji najpierw deklarujesz funkcję w pliku nagłówkowym w sekcji private lub public:

Kod: Zaznacz cały
private:
    void zlecenia(void);


a dopiero potem tworzysz definicję w pliku źródłowym:

Kod: Zaznacz cały
    void TForm1::zlecenia(void) // zwróć uwagÄ™ na to, że przypisaÅ‚em funkcjÄ™ do klasy formularza
    {
    IdFTP1->ChangeDir("Zlecenia");
    IdFTP1->List(ftp, "*.*", false);
    int ilosc = ftp->Count;
    int i=2;
       for (i; i < ilosc; i++)
       {
          String nazwa_pliku = ftp->Strings[i];
          String sciezka = "D:\\Baza\\Zlecenia\\" + nazwa_pliku;
          if(!FileExists(sciezka))
          {
          IdFTP1->Get(nazwa_pliku,sciezka,true,false);
          }
       }
       for (i=0; i < ilosc; i++)
       {
          ftp->Delete(i);
       }
    }





Wciąż robisz masę błędów. Napraw to, a zobaczymy co z tym dalej zrobić.
Poczytaj o funkcjach i przekazywaniu obiektów pomiędzy formularzami, gdyż chyba nie rozumiesz działania tego mechanizmu.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
PodziÄ™kowaÅ‚ : 12
OtrzymaÅ‚ podziÄ™kowaÅ„: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: [IndyFTP] Sprawdzanie czy istnieje plik

Nowy postprzez Michalos » niedziela, 2 listopada 2008, 14:14

Teraz te funkcje pobierające brakujące pliki działają poprawnie. Dzięki za te uwagi/krytykę w moją stronę, bardzo mi pomagają - ja się dopiero uczę, to chyba widać :P
Kod: Zaznacz cały
void TForm1::zlecenia(void)
{
IdFTP1->ChangeDir("Zlecenia");
IdFTP1->List(ftp, "*.*", false);
String nazwa_pliku;
String sciezka;
int i;
   for (i=2; i < ftp->Count; i++)
   {
      nazwa_pliku = ftp->Strings[i];
      sciezka = "D:\\Baza\\Zlecenia\\" + nazwa_pliku;
      if(!FileExists(sciezka))
      {
      IdFTP1->Get(nazwa_pliku,sciezka,true,false);
      }
   }
}
void TForm1::PDF_V(void)
{
   IdFTP1->ChangeDirUp();
   IdFTP1->ChangeDir("PDF_V");
   IdFTP1->List(ftp, "*.*", false);
   String nazwa_pliku, sciezka;
   int i;
   for (i=2; i < ftp->Count; i++) {
      nazwa_pliku = ftp->Strings[i];
      sciezka = "D:\\Baza\\PDF_V\\" + nazwa_pliku;
      if(!FileExists(sciezka)){
      IdFTP1->Get(nazwa_pliku,sciezka,true,false);
      }
   }
}
void TForm1::PDF_K()
{
   IdFTP1->ChangeDirUp();
   IdFTP1->ChangeDir("PDF_K");
   IdFTP1->List(ftp, "*.*", false);
   int i;
   for (i=2; i < ftp->Count; i++) {
      String nazwa_pliku = ftp->Strings[i];
      String sciezka = "D:\\Baza\\PDF_K\\" + nazwa_pliku;
      if(!FileExists(sciezka)){
      IdFTP1->Get(nazwa_pliku,sciezka,true,false);
      }
   }
}


Teraz mam problemik z funkcją wysyłającą brakujące pliki, teraz wygląda ona tak:
Kod: Zaznacz cały
void TForm1::zlecenia_ftp()
{
   FindDir(local, "d:\\Baza\\Zlecenia\\","");
   int ilosc= local->Count;
   int i;
   String nazwa_pliku, sciezka_ftp, sciezka_local;
   if(ilosc!=0)
   {
      for (i=0; i < ilosc; i++)
      {
      nazwa_pliku = local->Strings[i];
      sciezka_ftp = "\\Zlecenia" + nazwa_pliku;
      sciezka_local = "D:\\Baza\\Zlecenia\\" + nazwa_pliku;
      IdFTP1->ChangeDirUp();
      IdFTP1->ChangeDir("Zlecenia");
      try
      {
         IdFTP1->List(ftp,nazwa_pliku,false);
      }
      catch(EIdReplyRFCError& exc)
      {
      int exist = ftp->Count;
      if(exist!=1)
         {
         IdFTP1->Put(sciezka_local,sciezka_ftp,true);
         }
      }
      }
   }
}


nie jestem pewien czy dobrze obsługuję ten wyjątek. Ten wyjątek pojawia się, gdy próbuje użyć funkcji List(), dokładna treść komunikatu to:
First chance exception at $7C812AEB. Exception class EIdReplyRFCError with message '"/Zlecenia/0001 20080108 .BAK" File/Directory not found
'. Process Project1.exe (2504)

Czyli, nie ma takiego pliku na FTP, cały w tym sęk - jak go nie ma to ma go pobrać, lecz niestety nie chce tego zrobić. Możesz mi coś doradzić ?

EDIT ---------------------------------

Zrobiłem podobnie jak Ty na początku tematu napisałeś, czyli:
Kod: Zaznacz cały
void TForm1::zlecenia_ftp()
{
   FindDir(local, "d:\\Baza\\Zlecenia\\","");
   int ilosc= local->Count;
   int i;
   bool test;
   String nazwa_pliku, sciezka_ftp, sciezka_local;
   if(ilosc!=0)
   {
      for (i=0; i < ilosc; i++)
      {
      nazwa_pliku = local->Strings[i];
      sciezka_ftp = "\\Zlecenia" + nazwa_pliku;
      sciezka_local = "D:\\Baza\\Zlecenia\\" + nazwa_pliku;
      IdFTP1->ChangeDirUp();
      IdFTP1->ChangeDir("Zlecenia");
      test = true;
      try
      {
         IdFTP1->List(ftp,nazwa_pliku,false);
      }
      catch(...)
      {
       test=false;
      }

      if(test==false)
         {
         IdFTP1->Put(sciezka_local,sciezka_ftp,true);
         }
      }
      }

}

Ale nadal nic to nie zmienia.. ten sam błąd
Avatar użytkownika
Michalos
Bladawiec
Bladawiec
 
Posty: 35
Dołączył(a): niedziela, 19 października 2008, 11:45
PodziÄ™kowaÅ‚ : 1
OtrzymaÅ‚ podziÄ™kowaÅ„: 0
    NieznanyNieznana

Re: [IndyFTP] Sprawdzanie czy istnieje plik

Nowy postprzez Cyfrowy Baron » niedziela, 2 listopada 2008, 15:55

Teraz już nie wiem, ten Twj kod jest mocno zagmatwany. Prawdopodobnie masz coś źle zrobione przy porównywaniu plików.
Na początek sprawdź czy działa proste wysyłanie pliku, bez tych Twoich udziwnień, jeżeli działa to szukaj błędu w samym kodzie, a nie we właściwościach komponentu IdFTP.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
PodziÄ™kowaÅ‚ : 12
OtrzymaÅ‚ podziÄ™kowaÅ„: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: [IndyFTP] Sprawdzanie czy istnieje plik

Nowy postprzez Witold » niedziela, 2 listopada 2008, 17:45

Michalos napisał(a):
nie jestem pewien czy dobrze obsługuję ten wyjątek. Ten wyjątek pojawia się, gdy próbuje użyć funkcji List(), dokładna treść komunikatu to:
First chance exception at $7C812AEB. Exception class EIdReplyRFCError with message '"/Zlecenia/0001 20080108 .BAK" File/Directory not found
'. Process Project1.exe (2504)

Czyli, nie ma takiego pliku na FTP, cały w tym sęk - jak go nie ma to ma go pobrać, lecz niestety nie chce tego zrobić. Możesz mi coś doradzić ?

EDIT ---------------------------------

Zrobiłem podobnie jak Ty na początku tematu napisałeś, czyli:
Kod: Zaznacz cały
void TForm1::zlecenia_ftp()
{
   FindDir(local, "d:\\Baza\\Zlecenia\\","");
   int ilosc= local->Count;
   int i;
   bool test;
   String nazwa_pliku, sciezka_ftp, sciezka_local;
   if(ilosc!=0)
   {
      for (i=0; i < ilosc; i++)
      {
      nazwa_pliku = local->Strings[i];
      sciezka_ftp = "\\Zlecenia" + nazwa_pliku;
      sciezka_local = "D:\\Baza\\Zlecenia\\" + nazwa_pliku;
      IdFTP1->ChangeDirUp();
      IdFTP1->ChangeDir("Zlecenia");
      test = true;
      try
      {
         IdFTP1->List(ftp,nazwa_pliku,false);
      }
      catch(...)
      {
       test=false;
      }

      if(test==false)
         {
         IdFTP1->Put(sciezka_local,sciezka_ftp,true);
         }
      }
      }

}

Ale nadal nic to nie zmienia.. ten sam błąd


Uruchom ten program spoza IDE, sprawdź czy wtedy działa.
Wydaje mi się że gdy testujesz program w IDE, debuger pokazuje wyjątki mimo tego że są wyłapywane przez blok catch().
Avatar użytkownika
Witold
Konstrukcjonista
Konstrukcjonista
 
Posty: 223
Dołączył(a): piątek, 29 sierpnia 2008, 10:53
PodziÄ™kowaÅ‚ : 1
OtrzymaÅ‚ podziÄ™kowaÅ„: 14
Kompilator: bcb6, Turbo C++ Explorer
    NieznanyNieznana

Re: [IndyFTP] Sprawdzanie czy istnieje plik

Nowy postprzez Michalos » niedziela, 2 listopada 2008, 21:36

Czy taki kod może powodować zawieszenie się programu :shock:
Kod: Zaznacz cały
void TForm1::zlecenia_ftp()
{
   FindDir(local, "d:\\Baza\\Zlecenia\\","");
   IdFTP1->ChangeDirUp();
   IdFTP1->ChangeDir("Zlecenia");
   int ilosc= local->Count;
   int i;
   String nazwa_pliku, sciezka_ftp, sciezka_local;
   if(ilosc!=0)
   {
      for (i=0; i < ilosc; i++)
      {
      nazwa_pliku = local->Strings[i];
      sciezka_ftp = "\\Zlecenia\\" + nazwa_pliku;
      sciezka_local = "D:\\Baza\\Zlecenia\\" + nazwa_pliku;

      IdFTP1->Put(sciezka_local,sciezka_ftp,true);

      }
   }

}


Gdy zatrzymuje kompilowanie programu, sprawdzam jaka wartość ma zmienna ilosc, wynosi tyle ile powinna (79). Żadne komunikaty się nie pojawiają... pomaga jedynie reset programu z menu buildera. Wysyła kilka plików i zwiecha.
Avatar użytkownika
Michalos
Bladawiec
Bladawiec
 
Posty: 35
Dołączył(a): niedziela, 19 października 2008, 11:45
PodziÄ™kowaÅ‚ : 1
OtrzymaÅ‚ podziÄ™kowaÅ„: 0
    NieznanyNieznana

Re: [IndyFTP] Sprawdzanie czy istnieje plik

Nowy postprzez Cyfrowy Baron » poniedziaÅ‚ek, 3 listopada 2008, 09:53

Problemem może być liczba plików jakie wysyłasz na serwer, po prostu zanim wyślesz wszystkie pliki połączenie z serwerem ulega zerwaniu, a wtedy dalsze wysyłanie plików wywołuje po prostu błędy.
Używam klienta FTP z programu Total Commander UP i gdy wysyłam pliki na serwer czasami zdarza się, że następuje zerwanie połączenia i plików nie można wysłać. Program oczywiście obsługuje wyjątki i gdy nastąpi zerwanie połączenia to powiadamia o tym.



Powinieneś przed wysłaniem każdego pliku sprawdzić czy wciąż jesteś połączony z serwerem. Do sprawdzania połączenia służy funkcja Connected():

Przykład użycia:
Kod: Zaznacz cały
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
   if(IdFTP1->Connected())
    ShowMessage("PoÅ‚Ä…czony");
   else
   {
    ShowMessage("RozÅ‚Ä…czony");
    return;
   }

   TStrings *Lista = new TStringList;
   bool test = true;
   try{ IdFTP1->List(Lista, "index.html", false); }catch(...){test = false;}
   delete Lista;

   if(test == true)
    ShowMessage("Znaleziono plik");
   else
    ShowMessage("Brak pliku");
}
//---------------------------------------------------------------------------




Powinieneś również umieścić w programie komponent Timer a w nim co pewien czas (np. 20 sekund - Timer1->Interval = 20000) wysyłać polecenie NOOP w celu podtrzymania połączenia:
Kod: Zaznacz cały
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
    IdFTP1->Noop();
}
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
PodziÄ™kowaÅ‚ : 12
OtrzymaÅ‚ podziÄ™kowaÅ„: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana


  • 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