Wątek przeniesiony 2015-10-16 18:25 z Newbie przez furious programming.

Synchronizacja zawartości folderu ftp z folderem lokalnym

0

Witam

Z komponentami FTP Indy nie za wiele miałem wspólnego, dlatego pytam, bo z Google'owania niewiele wychodzi... ;-)

Mam listę plików (nazwa pliku + rozszerzenie) którą przechowuję w TstringList, nazwijmy ją Lista. Każda linijka to nazwa jednego pliku. Są to pliki znajdujące się w lokalnym katalogu (bez żadnych podkatalogów). Mam katalog na serwerze ftp, w którym powinny się znajdować takie same pliki (o takich samych nazwach) jak w katalogu lokalnym.
Chciałbym teraz w pętli, dla każdego z listy (Lista) plików lokalnych sprawdzić (po nazwie pliku) czy występuje także w katalogu na ftp.
Jeśli nie - nastąpiłoby jego przesłanie na ftp. Jeśli tak - nastąpiłoby sprawdzenie czy data modyfikacji pliku lokalnego jest młodsza niż pliku na ftp. Jeśli tak - nastąpiłoby jego przesłanie na ftp. Jeśli nie (jest taka sama lub starsza) - brak działania.
W zasadzie jestem w stanie stworzyć taki mechanizm jak opisałem. Problemem dla mnie pozostaje tylko w jaki sposób sprawdzić czy plik o danej nazwie znajduje się na ftp, i jaka jest data i czas jego modyfikacji.
Przyznam szczerze, że nie mam natomiast pomysłu jak usunąć pliki które znajdują się ftp, a nie ma ich w katalogu lokalnym (pobranie i porównanie listy plików lokalnej z listą ftp, a różnica z ftp do usunięcia???).
Fakt, że najprostszym rozwiązaniem byłoby usunięcie zawartości całego katalogu na ftp i przesłanie do niego całej zawartości katalogu lokalnego, ale chyba nie o to chodzi... ;-)

pozdrawiam
Wojtek

0

Najprosciej i najsensowniej jak masz taka mozliwosc to byloiby uzyc do tego Rsynca. Ale jak masz tylko mlotek to wszedzie widzisz gwozdzie:)

0

Pytanie było jak to zrobić w Delphi/FPC, a nie z użuciem rsync. Ja w Indy nie robię nic od wieków, jedynie bym wiedzial jak to zrobić pod Synapse. Na pewno TIdFtp ma metodę na pobranie listy plików z katalogu w przejrzystej formie albo nawet gotowe sprawdzenie czy istnieje w katalogu plik o danej nazwie. Ale jeśłi nie, to wyszukasz to na tej liśćie. Tak czy siak, potrzebujemy aby do tematu zajrzał @kAzek :)

0

A ja odpowiem jak zwykle jeżeli chodzi o Indy odwiecznym pytaniem... jaka wersja Indy (i dlaczego nie najnowsza) i Delphi?

EDIT:
Masz dla Indy 10 przykład jak pobrać listę z serwera (w przykładzie dodaje wszystko do ListView z 3 kolumnami (item i 2 subitem) i ViewStyle vsReport)
Mając te dane już chyb a powinieneś wiedzieć co zrobić.

        IdFTP.ChangeDir('nazwa folderu na ftp');
        //jeżeli IdFTP.CanUseMLS zwraca false dodaj do uses IdAllFTPListParsers
        //bo to oznacza ze na danej konfiguracji serwera nie zadziala MLS i do wypelnienia 
       //listy trzeba uzyc parsera (wystarczy dodac do uses wspomniany modul Indy reszte zalatwi)
        IdFTP.UseMLIS:= IdFTP.CanUseMLS;
        IdFTP.List;
        //w przykladzie dodaje znalezione do ListView
        for i:= 0 to IdFTP.DirectoryListing.Count - 1 do
        begin
          if IdFTP.DirectoryListing.Items[i].ItemType = ditFile then //interesuja nas tylko pliki (na liscie pobranych obiektow oprocz plikow mogą byc też foldery, dowiązania itd)
          begin
            ListItem:= ListView1.Items.Add;
            ListItem.Caption:= IdFTP.DirectoryListing.Items[i].FileName;  //nazwa pliku
            ListItem.SubItems.Add(IntToStr(IdFTP.DirectoryListing.Items[i].Size)); //rozmiar
            ListItem.SubItems.Add(DateTimeToStr(IdFTP.DirectoryListing.Items[i].ModifiedDate)); //data modyfikacji
          end;
        end;

Ogólnie z tą synchronizacja prosta sprawa masz listę plików z FTP i sprawdzasz z lokalną jak pliku nie ma na lokalu to go usuwasz z FTP (IdFTP.Delete('nazwa pliku');), później już tylko jeżeli plik jest na FTP porównujesz daty jeżeli różne wysyłasz jeżeli pliku nie ma tez wysyłasz...

0

Witam

W linijce Twojego kodu:

IdFTP1.UseMLIS:= IdFTP1.CanUseMLS; 

przy kompilacji otrzymuję błąd:

identifier idents no member "CanUseMLS"

Dodałem do uses IdAllFTPListParsers ale to też nie pomogło. Co może być nie tak?

0

Hmmm... Nikt nie wie co może być nie tak?

1

Oj może (nie wiem bo dawno nie aktualizowałem Indy bo nic takiego z jego wykorzystaniem nie robiłem) już wycofano zbędną właściwość i tak czy tak używa się parserów z IdAllFTPListParsers więc po prostu usuń tą linię i dodaj ten moduł do uses i powinno działać a jak nie to spróbuj IdFTP.UseMLIS:= False.

0

Witam

Kombinuję już kilka dni i niestety chyba niewłaściwie przeliczyłem swoje siły na zamiary... ;-)
Mam w StringList'ach odpowiednio (1 pozycja = 1 wiersz):

  • wykaz plików w katalogu lokalnym - Lista,
  • datę modyfikacji plików w katalogu lokalnym - ListaCzas,
  • wykaz plików w katalogu ftp - ListaFTP,
  • datę modyfikacji plików w katalogu ftp - ListaCzasFTP,
    Chodzi mi o uzyskanie mniej więcej takiego mechanizmu:
var
 Lista, ListaCzas, ListaFTP, ListaCzasFTP: TStringList;

while (elementy Lista) = 0 do
begin
 if (nazwa pliku z Lista istnieje na ListaFTP) then
   begin
     if (data modyfikacji (z ListCzas) pliku lokalnego (z Lista) jest mlodsza niz data (z ListaCzasFTP) pliku na ftp (z ListaFTP)) then
       begin
         // wysylka pliku na ftp
       end;
   end
    else
   begin
     // wysylka pliku na ftp
   end;
end;

if (elementy z Lista nie występują na ListaFTP) then
begin
  // usuwamy pliki na ftp których nazwy nie występują na Lista
end;

Ma ktoś jakiś pomysł jak to ubrać. Na ew. wszelkie inne rozwiązania zmierzające do osiągnięcia podobnego efektu także jestem otwarty..

0

Brakuje tylko listy z zawartością pierwszego wiersza, listy rozmiarów pliku i listy zakupów w Biedronce na pojutrze. No zlituj się! Przecież TStringList, może przechowywać obiekty. Nie lepiej zrobić coś w guście poniżej [jeśli jest jakiś wyciek pamięci lub coś źle zwolniłem lub przypisał, to proszę poprawcie mnie]. Kod pisany pod Delphi 7 i ze wsparciem dla Ansi, ale nie problem sobie typy zamienić ze string na WideString. I odpowiedniki typów oraz funkcji na te z W na końcu. Gdybyś potrzrbował Unicode. Nie wiem jak ze wsparciem tego po stronie FTP i samego Indy, ale powinno dać się ogarnąć.

//...
var
  I : integer;
  H : THandle;
  Path : string;
  SL : TStringList;
  WFD : TWIN32FindData;
  WFDPtr : PWin32FindDataA;
begin
  Path := 'D:\*.*';
  SL := TStringList.Create;
  H := Windows.FindFirstFile(PChar(Path), WFD);
  if H <> INVALID_HANDLE_VALUE then
  begin
    try
      repeat
        if (WFD.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY = 0) then
        begin
          New(WFDPtr);
          WFDPtr^ := WFD;
          SL.AddObject(WFD.cFileName, TObject(WFDPtr));
        end;
      until not FindNextFile(H, WFD);
    finally
      Windows.FindClose(H);
    end;
  end;
  if SL.Count > 2 then
  begin
    WFDPtr := PWin32FindDataA(SL.Objects[2]);
    ShowMessage(WFDPtr.cFileName + ' = ' + IntToStr(WFDPtr.nFileSizeLow) + ' bajtów');
  end;
  for I := SL.Count - 1 downto 0 do
  begin
    WFDPtr := PWin32FindDataA(SL.Objects[I]);
    Dispose(WFDPtr);
    SL.Delete(I);
  end;
  SL.Free;
end;
//...

Oczywiście najlepiej zrobić to w wątku jeśli plików jest dużo (a nawet jeśli nie to tak będzie lepiej i tak). Ścieżkę do plików to już sobie pobierz po swojemu. Ja zapodałem przykładową D:\. Pokazanie trzeciego elementu na liście - jeśli istnieje - to tylko przykład. Żebyś wiedział jak to wyświetlać.

Natomiast co do sprawdzania czy plik jest na serwerze, wysłania go oraz ewentualnego pobrania. To umiał bym ogarnąć to tylko pod Synapse. Ty upierasz się przy Indy, więc tutaj - jezeli w dokumentacji (btw - właśnie, dlaczego unikasz dokumentacji? Bo Indy zdaje się jak każdy porządny projekt też ją raczej posiada i przykłady na pewno też [?]) nie wiadomo jak rozwiązać dany problem. To na tym forum pozostaje tylko @kAzek, ewentualnie inni którzy jeszcze na przykład nie przekonali się i nie przesiedli się na Synapse ;) Chociaż pewnie @kAzek też czasem uzywa/ł Synapse, ale ogarniąjącego w pełni Indy to kojarze tylko Jego.

1 użytkowników online, w tym zalogowanych: 0, gości: 1