Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - EXIT verlässt Proc nicht??


D. Annies - Mo 08.01.07 15:57
Titel: EXIT verlässt Proc nicht??
Hi, Delpher,

Warum verlässt EXIT oder die Boolesche Variable "raus"/true nicht die Prozedur, bzw. wie wird die Rekursion richtig bei 'Abbruch' verlassen?

Ich habe zur Sicherheit den vollständigen Proc-Code angegeben.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
Procedure TForm1.FindFiles (aPath, aFindMask: String; aWithSub: Boolean; aResult: tStrings);
Var  FindRec                       : tSearchRec;
     existingfilename, pr_filename : string;
     dname, uvname                 : string;
     n, erg                        : integer;
     raus                          : boolean;
Begin
  raus := false;
  If (aPath = ''or (aFindMask = ''or Not Assigned (aResult) Then  Exit;
  If aPath[Length(aPath)] <> '\' Then  aPath := aPath + '\';
  meldung := '';
  If FindFirst (aPath + aFindMask, faAnyFile - faDirectory, FindRec) = 0 Then
  Repeat
    If (FindRec.Name <> '.'and (FindRec.Name <> '..'Then
    begin
      if IsfileInUse(aPath + findrec.Name) = true then
      begin
        dname := Findrec.Name;
        if extractfileext(dname) = '.dbf' then schliesse_DBTab(self);
      end;
      if IsfileInUse(aPath + findrec.Name) = false then //prüfen, ob Datei in Benutzung ist
        aResult.Add (aPath + FindRec.Name);  // ...Ergebnis in die Stringlist einfügen
// showmessage(findrec.Name+' *** '+ Datetostr(FileDateToDateTime(FileAge(apath+FindRec.Name)))+'+++'+datetostr(now));
      if FileDateToDateTime(FileAge(apath+FindRec.Name)) < now //or
        {(daysbetween(FileDateToDateTime(FileAge(apath+'\'+FindRec.Name)), now) <= strtoint(edit5.Text))} then
      begin  //incDay(
        if (FindRec.Name[1] = '_'or (pos('.~', FindRec.Name) > 0then
        begin
          showmessage(apath + findrec.name + ' wird gelöscht');
          DeleteFile(apath + FindRec.name)
        end
        else
        if (pos('.pas', FindRec.Name) > 0or (pos('.dfm', FindRec.Name) > 0or
           (pos('.dcu', FindRec.Name) > 0or (pos('.exe', FindRec.Name) > 0or
           (pos('.dpr', FindRec.Name) > 0or (pos('.ddp', FindRec.Name) > 0or
           (pos('.dof', FindRec.Name) > 0or (pos('.dsk', FindRec.Name) > 0then begin end
        else
        begin
          uvname := '';
          for n := pos('Buecherei\', apath)+10 to length(apath) do
            uvname := uvname + apath[n];

          ExistingFilename := apath + FindRec.name;

          if apath[1] = label38.Caption[1then  // von zB. F: nach zB. C: = Rücksicherung
          begin                                          // Stick nach Platte(oder 2.Stick)
            if label30.Caption[length(label30.Caption)] = '\' then
              Pr_FileName := label30.caption + uvname + FindRec.name
            else
              Pr_FileName := label30.caption + '\' + uvname + FindRec.name  // zu Beginn
          end
          else
          if apath[1] = label30.Caption[1then  // von zB. C: nach zB. F: = Datensicherung
          begin                                          // Platte(oder 2.Stick) nach Stick)
            if label38.Caption[length(label38.Caption)] = '\' then
              Pr_FileName := label38.caption + uvname + FindRec.Name
            else
              Pr_FileName := label38.caption + '\' + uvname + FindRec.Name; // am Ende
          end;

          if fileexists(Pr_FileName) then
          begin
            if FileDateToDateTime(FileAge(Pr_FileName)) <> FileDateToDateTime(FileAge(existingfilename)) then
            begin
              erg := xmessagedlg('Soll    ' + pr_filename+ ' '+datetimetostr(filedatetodatetime(FileAge(Pr_Filename))) +#13+
                          'durch '   + existingfilename+ ' '+datetimetostr(filedatetodatetime(FileAge(ExistingFileName))) +#13+
                          ' ersetzt werden?', mtConfirmation, [mbYes, mbno, mbcancel], ['ja''nein''Abbrechen'], self.font);

              case erg of mryes    : CopyFile(PChar(ExistingFileName), PChar(Pr_FileName), FALSE);
                          mrcancel : raus := true;  //EXIT;
              end;
            end;
          end
          else
          begin
            if not (label30.Caption[length(label30.Caption)] = '\'then
              label30.Caption := label30.Caption + '\';
            erg := xmessagedlg('Soll '+ pr_filename + ' angelegt werden?', mtConfirmation,
                     [mbYes, mbNo, mbcancel], ['ja''nein''Abbrechen'], self.font);
            case erg of mryes    : begin
                                     if not directoryexists(label30.caption+uvname) then
                                       forcedirectories(label30.caption+uvname);
                                     CopyFile(PChar(ExistingFileName), PChar(Pr_FileName), TRUE);
                                   end;
                        mrcancel : raus := true;  //EXIT;
            end;
          end;
        end;
      end
      else showmessage('???');
    end;
  Until FindNext (FindRec) <> 0;
  FindClose (FindRec);

  If (Not aWithSub) or (raus) Then  Exit;    // keine Unterverzeichnisse vorhanden dann raus
  If FindFirst (aPath + '*.*', faAnyFile, FindRec) = 0 Then
  Repeat     // In Unterverzeichnissen weiter suchen
    If (FindRec.Name <> '.'and (FindRec.Name <> '..'Then
      If Boolean (FindRec.Attr and faDirectory) Then  // ob es sich um ein Verzeichnis handelt
        If ((FindRec.Attr and faDirectory) <> 0then
          FindFiles (aPath + FindRec.Name, aFindMask, aWithSub, aResult); // Rekursion
  Until FindNext (FindRec) <> 0;
  FindClose (FindRec);   // showmessage(meldung);
End;



Danke für Hilfe, sagt Detlef A.


Coder - Mo 08.01.07 16:06

Probier mal ab Zeile 100

Delphi-Quelltext
1:
2:
3:
4:
5:
If ((FindRec.Attr and faDirectory) <> 0then
        begin
          FindFiles (aPath + FindRec.Name, aFindMask, aWithSub, aResult); // Rekursion
          if raus then Exit;
        end;


Ist nur geraten.

Edit// War quatsch.


Narses - Mo 08.01.07 16:18

Moin!

Exit beendet nur die aktuelle Instanz einer Prozedur, nicht den gesamten rekursiven Aufruf. :? Ich gebe allerdings zu, habe den Code max. "überflogen"... :|

cu
Narses


Chatfix - Mo 08.01.07 16:58

Ich habe auch nur überfolgen, aber du solltest vielleicht die Variable "raus" global definieren und nicht lokal.

Dann müsste er auch bei den rekursiven Durchläufen rausspringen.
"raus" musst du natürlich dann vor dem ersten Aufruf der Prozedur einmal auf false setzen, und nicht jedesmal rekursiv in der Prozedur.


Christian S. - Mo 08.01.07 17:02

Könnte man nicht eine Exception werfen, welche dann "nach oben" weiter gereicht wird?


Martok - Mo 08.01.07 17:07

user profile iconChristian S. hat folgendes geschrieben:
Könnte man nicht eine Exception werfen, welche dann "nach oben" weiter gereicht wird?

Autsch. Das meinst du jetzt nicht ernst, oder? Exceptions sind Ausnahmen, kein Mittel zur Flusskontrolle.

Für sowas sollte die rekursive Funktion eher einen Rückgabewert bekommen, der den aufrufenden Funktionen sagt: beende dich!


Christian S. - Mo 08.01.07 17:19

user profile iconMartok hat folgendes geschrieben:
user profile iconChristian S. hat folgendes geschrieben:
Könnte man nicht eine Exception werfen, welche dann "nach oben" weiter gereicht wird?

Autsch. Das meinst du jetzt nicht ernst, oder? Exceptions sind Ausnahmen, kein Mittel zur Flusskontrolle.
Zum einen sehe ich keinen Grund, mir meine Möglichkeiten selber zu verbauen und sklavisch und undifferenziert an irgendwelchen Regeln festzuhalten. Zum anderen ist ein solches Beenden einer Rekursion wohl eine Ausnahme, denn im Normalfall sollte das bei einer Rekursion nicht nötig sein.


D. Annies - Mo 08.01.07 17:57

Hi, Delpher,

scheint ja gar nicht so einfach zu sein..., obwohl ich meine, dass ich vor der eigentlichen Rekursion abbrechen will.

Das mit der globalen Variablen habe ich überprüft - njet.

Bis denne, Detlef


jasocul - Mo 08.01.07 18:03

Du musst Dein "raus" "durchreichen". Sonst weiß die aufrufende Prozedur ja nicht, dass die Rekursion ein Abbruch-Kriterium bekommen hat. Das ginge zum Beispiel mit einem Var-Parameter des Prozeduraufrufs. Zusätzlich solltest Du den Wert von "raus" auch in Deinen Schleifen abfragen, damit diese nicht weiterlaufen.


D. Annies - Mo 08.01.07 19:00

Hi, Peter,

das hört sich gut an, ich versuch's mal und melde mich dann wieder...

bis denne, Detlef


D. Annies - Mo 08.01.07 19:51

HI, ...

ich krieg's nicht hin!
Habe die Deklaration ergänzt durch ...(...; var raus: boolean);
setze in der Proc raus auf true,
und rufe mit ...(..., raus) wieder auf

kompiliert fehlerfrei, aber bricht nicht ab. Ich habe zwar schon mit var-Parametern gearbeitet, aber ich sehe hier den Fehler nicht.

Kann nochmal jemand helfen?

Danke, Detlef


D. Annies - Mo 08.01.07 20:39

Ha, es hat sich doch etwas (eine Menge) getan:

Die Rekursion wird abgebrochen, wenn das aktuelle Verzeichnis abgefragt ist, ein Wechsel in ein andreres UV findet nicht mehr statt!

Das ist es dann wohl - noch mals danke für den VAR-Tipp!

Gruß, Detlef