Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Rekursiver Aufruf von FTPFindFirstFile (https://www.delphipraxis.net/115086-rekursiver-aufruf-von-ftpfindfirstfile.html)

hsbc 5. Jun 2008 14:16


Rekursiver Aufruf von FTPFindFirstFile
 
Hallo allerseits,

ich möchte mittels FTPFindFirstFile ein Server-Verzeichnis mit allen Unterverzeichnissen einlesen und in einer TreeView speichern.

Die erste Ebene funktioniert auch einwandfrei, nur ein rekursiver Aufruf von FTPFindFirstFile schlägt insofern fehl, dass die Routine nil zurückliefert, also keine weiteren Daten.

Jetzt meine Fragen:

1. Weiss jemand, wie man FTPFindFirstFile rekursiv aufrufen kann?
2. Sollte dies nicht möglich sein, kennt jemand eine Möglichkeit, mittels Indy (List) in eine TreeView zu speichern?

mfg
Herbert

shmia 5. Jun 2008 15:55

Re: Rekursiver Aufruf von FTPFindFirstFile
 
Hast du vielleicht "\" anstelle von "/" als Trennzeichen verwendet?
Zeig mal Sourcecode!

hsbc 5. Jun 2008 18:43

Re: Rekursiver Aufruf von FTPFindFirstFile
 
Hier der entsprechende Quellcode:

Delphi-Quellcode:
procedure TForm1.FindFilesTree(aTree: tTreeView; aPath: string; aNode: tTreeNode; aWithFiles: boolean);
var
  NodeTmp: tTreeNode;
  Info: pNodeInfo;
  hSearch: HINTERNET;
  findData: WIN32_FIND_DATA;
begin
  aTree.Items.BeginUpdate;

  if aPath = '' then aPath := '/';
  if aPath[Length(aPath)] <> '/' then aPath := aPath + '/';

  if FTPSetCurrentDirectory(hConnect, PChar(aPath)) then begin
    hSearch := FTPFindFirstFile(hConnect, nil, findData, INTERNET_FLAG_DONT_CACHE, 0);
    if hSearch = nil then
    begin
      ; // Fehler
    end
    else begin
      repeat
        if findData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY then
        begin       // Eintrag = Verzeichnis
          if (findData.cFileName[1] <> '.') then
          begin
            New(Info);
            Info^.Path := true;
            Info^.Name := aPath + findData.cFileName;
            // zum aktuellen Eintrag hinzufügen
            aNode := aTree.Items.AddChildObject(aNode, findData.cFileName, Info);
          end;

          // Knoten merken
          NodeTmp := aNode.Parent;
          // rekursiver Aufruf
          FindFilesTree(aTree, aPath+findData.cFileName, aNode, aWithFiles);
          // Gemerkten Knoten lesen
          aNode := NodeTmp;
        end
        else begin  // Eintrag = Datei
          if aWithFiles then
          begin
            ;
          end;
        end;
      until not InternetFindNextFile(hSearch, @findData);
      InternetCloseHandle(hSearch);
    end;
  end;

  aTree.Items.EndUpdate;
end;
Wie gesagt, die erste Verzeichnisebene wird richtig in den Tree geschrieben. Der rekursive Aufruf gibt bei hSearch nil zurück.

mfg
Herbert

p0w3r5tr34m3r 5. Jun 2008 21:40

Re: Rekursiver Aufruf von FTPFindFirstFile
 
muss es unbedingt mit FTPFindFirstFile sein?

Hab hier was mit den standard Indy (v. 10) Kompos gemacht...

Delphi-Quellcode:
procedure TWorkerThread.ListDir(dir: String; const tv: TTreeView; var tn: TTreeNode);
var
  itm: TIdFTPListItems;
  i: Integer;
  node: TTreeNode;
  tmp: string;
begin
  thread.ftp.ChangeDir(dir);
  thread.ftp.List;
  itm := thread.ftp.DirectoryListing;
  for i := 0 to itm.count-1 do begin
    if itm.Items[i].ItemType = ditDirectory then begin
      node := form1.treeview1.Items.AddChild(tn, itm.Items[i].Filename);
      listdir(itm.items[i].filename, form1.treeview1, node);
      ftp.ChangeDirUp;
      ftp.list;
      itm := thread.ftp.DirectoryListing;
    end
    else
      form1.treeview1.Items.addChild(tn, itm.Items[i].filename+' ['+inttostr(itm.items[i].size)+']');
  end;
end;
musste deinen vorstellungen evtl. noch anpassen aber funktioniert auch rekursiv :-)


MfG

hsbc 6. Jun 2008 06:55

Re: Rekursiver Aufruf von FTPFindFirstFile
 
Hallo p0w3r5tr34m3r,

vielen herzlichen Dank.

Nachdem diese Routine vom Prinzip her gleich auf Anhieb funktionierte, habe ich mich doch entschlossen, das ganze mit Indy(10) zu verwirklichen. Hier dürfte Indy doch die Nase vorne haben.

mfg
Herbert

momo54321 18. Mär 2012 09:22

AW: Rekursiver Aufruf von FTPFindFirstFile
 
hi,
bin noch neu im thema delphi.
wie ruf ich denn die procedure auf?

so gehts leider nicht:
Delphi-Quellcode:
ListDir('/public_html/install2/',Treeview1,'/');
Code:
[DCC Error] Unit1.pas(1806): E2010 Incompatible types: 'TTreeView' and 'TTreeNode'

Bummi 18. Mär 2012 09:47

AW: Rekursiver Aufruf von FTPFindFirstFile
 
Wie sieht denn Deine Prozedur aus, die aus #4 kann es ja nicht sein ... dann wäre der 3. Parameter falsch, nicht der 2.

whiteF 18. Mär 2012 12:00

AW: Rekursiver Aufruf von FTPFindFirstFile
 
hi, doch, der aus #4.

ich habe noch nie mit nodes und treeview gearbeitet, deswegen weiss ich nich in wie fern da was hin muss.

himitsu 18. Mär 2012 12:10

AW: Rekursiver Aufruf von FTPFindFirstFile
 
Ich hab's jetzt auch nicht im Kopf, aber die OH oder ein Tutorial zum TTreeView wird bestimmt helfen. (alternatif auch die Forensuche)

Bummi 18. Mär 2012 12:14

AW: Rekursiver Aufruf von FTPFindFirstFile
 
die Meldung wenn o.g. Prozedur verwenden würdest wäre
Code:
[DCC Fehler] xxxx.pas(30): E2033 Die Typen der tatsächlichen und formalen Var-Parameter müssen übereinstimmen
Deine Prozedur scheint als 2. Parameter eine Treenode zu erwarten ...

momo54321 18. Mär 2012 12:17

AW: Rekursiver Aufruf von FTPFindFirstFile
 
respekt vor deinen ganzen beiträgen hier im forum.
aber ich hab schon geschaut und an diesem sonntag, wollte ich auch mal etwas faul sein anstatt mich jetzt einige stunden in irgendetwas rein zu lessen, was ich höchstwahrscheinlich nie wieder nutzen werde. deshalb wäre es nett wenn mir jmd etwas nahe bringen könnte.

Bummi 18. Mär 2012 12:42

AW: Rekursiver Aufruf von FTPFindFirstFile
 
@momo54321

dafür habe ich volles Verständnis, aber mir geht es genauso ...
Die Meldung passt nicht zu Deiner Beschreibung, zum Glaskugeln :glaskugel: fehlt uns heute die Muße ...
Wenn Du etwas von Deinem Code (gegf. als Zip) hochlädst kann Dir sicher besser geholfen werden

momo54321 18. Mär 2012 12:51

AW: Rekursiver Aufruf von FTPFindFirstFile
 
ich hab eine idftp komponente auf meiner form. ich will nun mittels diesem script ein ordner auf einem ftp server löschen.
da man zum löschen jeden ordner/datei selbst zum löschen anweisen muss, muss ich wissen wo und wieviel ordner/dateien vorhanden sind.
hierbei hilft mir dieses script (mehr oder weniger oO ). Nachdem ich dann alles ausgelesen habe würde ich eine löschschleife einbauen.

hier ist mein code was dieses script angeht:

Delphi-Quellcode:
procedure ListDir(dir: String; const tv: TTreeView; var tn: TTreeNode);
var
  itm: TIdFTPListItems;
  i: Integer;
  node: TTreeNode;
  tmp: string;
begin
  Form1.ftp.ChangeDir(dir);
  Form1.ftp.List;
  itm := Form1.ftp.DirectoryListing;
  for i := 0 to itm.count-1 do begin
    if itm.Items[i].ItemType = ditDirectory then begin
      node := form1.treeview1.Items.AddChild(tn, itm.Items[i].Filename);
      listdir(itm.items[i].filename, form1.treeview1, node);
      Form1.ftp.ChangeDirUp;
      Form1.ftp.list;
      itm := Form1 .ftp.DirectoryListing;
    end
    else
      form1.treeview1.Items.addChild(tn, itm.Items[i].filename+' ['+inttostr(itm.items[i].size)+']');
  end;
end;

procedure TForm1.PngSpeedButton1Click(Sender: TObject);
var z, z1, z2, zahler: Integer;
List : TList;
ff : TIdFtpListItems;
begin

ListDir('/public_html/install2/', Treeview1, Treeview1.Items); // irgendwas passt nicht bez. TTreeNode
end;

Bummi 18. Mär 2012 12:58

AW: Rekursiver Aufruf von FTPFindFirstFile
 
Delphi-Quellcode:
procedure ListDir(dir: String; const tv: TTreeView; tn: TTreeNode);
statt
//procedure ListDir(dir: String; const tv: TTreeView; var tn: TTreeNode);
und dann

Delphi-Quellcode:
// wenn Du schon einen Knoten hast z.B.
ListDir('/public_html/install2/', Treeview1, Treeview1.Items[0]);
// wenn Du noch keinen Knoten hast
ListDir('/public_html/install2/', Treeview1, nil);

außerdem alle form1.treeview1. in der Prozedur durch tv. ersetzen ....

momo54321 18. Mär 2012 13:24

AW: Rekursiver Aufruf von FTPFindFirstFile
 
startbar ist es nun

aber nun hängt er in einer endlosscheife fest.
ich glaube die änderungen sind nicht richtungsweisend, da in posting #5, eigentlich von beginn an alles funktionierte.

showmessage hinzugefügt, um zu testen: die 2 showmessage's werden immer wieder aufgerufen...
Delphi-Quellcode:
procedure ListDir(dir: String; const tv: TTreeView; tn: TTreeNode);
var
  itm: TIdFTPListItems;
  i: Integer;
  node: TTreeNode;
  tmp: string;
begin
  Form1.ftp.ChangeDir(dir);
  Form1.ftp.List;
  itm := Form1.ftp.DirectoryListing;
  for i := 0 to itm.count-1 do begin
  showmessage(InttoStr(itm.count-1));    // Showmessage
    if itm.Items[i].ItemType = ditDirectory then begin
      if (itm.Items[i].Filename <> '.') or (itm.Items[i].Filename <> '0') then begin
      node := tv.Items.AddChild(tn, itm.Items[i].Filename);
      showmessage(itm.Items[i].Filename + ' / L: ' + IntToStr(Length(itm.Items[i].Filename)));     // Showmessage
      listdir(itm.items[i].filename, tv, node);
      Form1.ftp.ChangeDirUp;
      Form1.ftp.list;
      itm := Form1.ftp.DirectoryListing;
      end;
    end
    else
      form1.treeview1.Items.addChild(tn, itm.Items[i].filename+' ['+inttostr(itm.items[i].size)+']');
  end;
end;

himitsu 18. Mär 2012 13:30

AW: Rekursiver Aufruf von FTPFindFirstFile
 
Ich weiß nicht was daran so schwer ist, mal kurz selber in die OH zu schauen? Das wäre schneller gegangen, als hier zu fragen und andere erst nachsehn lassen zu müssen.

In deiner Funktion findest du, daß dieses aNode an AddChildObject übergeben wird und da kann man nachlesen, daß man für NIL angeben kann/muß, wenn man zum Beispiel den Rootknoten haben möchte, bzw. einen Hauptknoten erstellen will.
Beim TTreeView gibt man NIL an, wärend man z.B. beim VirtualTreeView das RootNode-Property verwendet, wenn ich mich richtig erinnere.

Und genau dafür gibt es Tutorials und die OH. :roll:

momo54321 18. Mär 2012 13:40

AW: Rekursiver Aufruf von FTPFindFirstFile
 
das angeben von nil geht allerdings auch nur wenn man im proceduren kopf das var entfernt.
nil hatte ich ja schon ausprobiert und es ging nicht, siehe Fehler:
Delphi-Quellcode:
[DCC Error] Unit1.pas(1837): E2033 Types of actual and formal var parameters must be identical



also, so funktioniert der kram zumindest bei mir nun:
Delphi-Quellcode:
procedure ListDir(dir: String; const tv: TTreeView; tn: TTreeNode);
var
  itm: TIdFTPListItems;
  i: Integer;
  node: TTreeNode;
  tmp: string;
begin
  Form1.ftp.ChangeDir(dir);
  Form1.ftp.List;
  itm := Form1.ftp.DirectoryListing;
  for i := 0 to itm.count-1 do begin
  //showmessage(InttoStr(itm.count-1));    // Showmessage
    if itm.Items[i].ItemType = ditDirectory then begin
      if itm.Items[i].Filename <> '.' then begin
      node := tv.Items.AddChild(tn, itm.Items[i].Filename);
      //showmessage(itm.Items[i].Filename + ' / L: ' + IntToStr(Length(itm.Items[i].Filename)));     // Showmessage
      listdir(itm.items[i].filename, tv, node);
      Form1.ftp.ChangeDirUp;
      Form1.ftp.list;
      itm := Form1.ftp.DirectoryListing;
      end;
    end
    else
      form1.treeview1.Items.addChild(tn, itm.Items[i].filename+' ['+inttostr(itm.items[i].size)+']');
  end;
end;

procedure TForm1.PngSpeedButton1Click(Sender: TObject);
begin

FTP.Host    := FTP.Text;
FTP.Port    := StrToInt(FTPport.Text);
FTP.Username := FTPlogin.Text;
FTP.Password := FTPpw.Text;

FTP.Connect;

ListDir('/public_html/install2/', Treeview1, nil);

FTP.Disconnect;
end;

himitsu 18. Mär 2012 13:50

AW: Rekursiver Aufruf von FTPFindFirstFile
 
Jupp, das VAR ist dort sowieso falsch.
Ich war aber eh von dem ursprünglichen
Delphi-Quellcode:
procedure TForm1.FindFilesTree(aTree: tTreeView; aPath: string; aNode: tTreeNode; aWithFiles: boolean);
ausgegangen.

sx2008 18. Mär 2012 14:09

AW: Rekursiver Aufruf von FTPFindFirstFile
 
Bei dem Auflisten eines Verzeichnis über FTP muss man richtig vorgehen.
FTP Zugriffe sind teuer da sie über das Netzwerk gehen und dementsprechend viel Zeit brauchen.
Daher muss die Strategie so aussehen:
Verzeichnis mit "List" abrufen und alle Dateien in den Tree eintragen.
Unterverzeichnisse werden in diesem 1. Durchlauf ignoriert.
In einem 2. Durchlauf durch ftp.DirectoryListing werden alle Unterverzeichnisse rekursiv besucht.
Ein erneutes Auflisten des aktuellen Verzeichnis ist dabei unnötig und muss unbedingt vermieden werden!!

Sehr zu empfehlen ist auch die Übergabe einer Rekursionstiefe:
Delphi-Quellcode:
procedure ListDir(dir: String; const tv: TTreeView; tn: TTreeNode; level:integer);
begin
  if level <= 0 then Exit;
  ...
  // und später der rekursive Aufruf
  listdir(itm.items[i].filename, tv, node, level - 1);
...
Möchte man nur das Basisverzeichnis auflisten übergibt man für "level" den Wert 1;
um alle Unterverzeichnisse aufzulisten übergibt man einen Wert > 100.
Das sollte für alle "normalen" FTP Server ausreichen.
Bei einem unbekannten FTP-Server könnte man mit level=2 beginnen, damit man sich nicht in den möglichweise Tausenden Unterverzeichnissen verliert.


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:40 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz