Autor Beitrag
LokutusvB
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 74

WinXP
Delphi 5, Delphi XE
BeitragVerfasst: Mi 17.10.07 10:54 
Hallo Leute,

ich habe ein Problem mit FindFirst. Ich möchte in einer Ordnerstruktur alle Unterordner und Dateien löschen. Nur geht das Programm bis in die tiefste Ordnerstruktur, löscht die Dateien und das war es. Etwas anderes kommt für mich leider nicht in Frage, da teilweise schreibgeschütze Dateien vorhanden sind, und die ShellAPI dort abbricht.

Findet jemand den Fehler? Ich komme momentan nicht mehr weiter.

ausblenden 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:
function TForm_Cleaner.leereOrdner(sStart: String): Boolean;
var
  srAkt: TSearchRec;
  sPfad: String;

begin
  Result := True;
  sPfad := sStart + '\';
  if (FindFirst(sPfad + '*.*', faAnyFile, srAkt) = 0) then begin
    REPEAT
      if (((srAkt.Attr and faDirectory) = faDirectory)) then if ((srAkt.Name <> '.') and (srAkt.Name <> '..'))
        then leereOrdner(sPfad + srAkt.Name);
    UNTIL FindNext(srAkt) <> 0;
  end;
  if (FindFirst(sPfad + '*.*', faAnyFile, srAkt) = 0) then begin
    REPEAT
    // ShowMessage(sPfad);
    if (((srAkt.Attr and faDirectory) = faDirectory) and (DirectoryIsEmpty(sPfad + srAkt.Name)) and (srAkt.Name <> '.') and (srAkt.Name <> '..'))
        then try
        ShowMessage (sPfad + srAkt.Name);
        RemoveDir(sPfad + srAkt.Name);
        except Result := False; end;
    if (((srAkt.Attr and faDirectory) <> faDirectory) and (srAkt.Name <> '.') and (srAkt.Name <> '..') and (srAkt.Attr <> faReadOnly))
        then try DeleteFile(sPfad + srAkt.Name); except Result := False; end;
    UNTIL FindNext(srAkt) <> 0;
  end;
end;


MFG
LokutusvB
Logikmensch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 390

Win XP
Delphi 2007 Prof., XE2, XE5
BeitragVerfasst: Mi 17.10.07 11:58 
Hallo, ich habe Deine Funktion mal ein bisschen umgebaut. Im Wesentlichen sollte sie dasselbe tun, was Du möchtest. Wichtig ist auch das FindClose am Ende.
Die Routine ist momentan noch so geschrieben, dass sie auch komplett abbricht, falls irgendeine Datei nicht gelöscht werden kann.
Im Zweifelsfalle solltest Du vor dem Löschen einer Datei auch die Dateiattribute System und Versteckt zurücksetzen. Dann sollten sich Dateien, die sonst von niemandem geöffnet sind, gelöscht werden können.

ausblenden volle Höhe 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:
function TForm_Cleaner.leereOrdner(sStart: String): Boolean;  
var  
  srAkt: TSearchRec;  
  sPfad: String;  
  ok:boolean;
begin  
  Result := True;  
  sPfad := includetrailingpathdelimiter(sStart);  
  ok:=FindFirst(sPfad + '*.*', faAnyFile, srAkt)=0;
  count:=0;
  while ok and result do begin
    if (srAkt.Name <> '.') and (srAkt.Name <> '..') then begin
      //Ab hier nur Verzeichnisse und Dateien
      if srAkt.Attr and faDirectory=faDirectory then begin
        //Ab hier Unterverzeichnis rekursiv löschen:
        if not leereOrdner(sPfad+srAkt.Name) then result:=false;
      end
        else begin
          //Ab hier Datei löschen:
          try
            DeleteFile(sPfad+srAkt.Name);
            if FileExists(sPfad+srAkt.Name) then result:=false; //<---
          except
            result:=false;
          end; {try}
        end; {else}
    end;
    ok:=FindNext(srAkt)=0;
  end;  
  //Verzeichnis sollte jetzt leer sein, also löschen:
  if result then begin
    try
      RemoveDir(sStart);
      if not DirectoryIsEmpty(sStart) then result:=false; //<---
    except
      result:=false;
    end;
  end; 
  FindClose(srAkt);
end;

_________________
Es gibt keine Probleme - nur Lösungen!
LokutusvB Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 74

WinXP
Delphi 5, Delphi XE
BeitragVerfasst: Mi 17.10.07 12:51 
Titel: Interner Speicherfehler
Leider funktoniert das genauso gut bzw. genau so schlecht wie mein Ansatz.

Zum Test habe ich mir extra eine Ordnerstruktur frei von versteckten oder geschützen Ordnern und Dateien angelegt. Die Dateien löscht es, aber die Ordner bleiben erhalten, maxmimal wird der tiefste Ordner gelöscht, in dem es vorher Dateien gab.

Lösche ich dir Ordner einzeln mit Pfadangabe (RemoveDir), werden sie gelöscht.

Ich gehe hier jetzt auf Nummer sicher und speicher jeden Ordner in eine Stringlist und klappere dann die Liste ab, vielleicht geht das ja besser.


Zuatz:
Das liegt nicht an der Routine, sondern am Prozess selbst. Egel welche Routine, sobald ein Verzeichis mit FindFirst/Next in Berührung gebracht wurde, selbst wenn danach FindClose aufruft, erscheint bir RmDire ein E/A-Fehler.

Hat jemand schon mal das gleiche beobachtet und weiss Abhilfe?

Zusatz 2:
Das Problem liegt daran, dass der Prozess selbst das Verzeichnis noch nicht wieder freigeben hat, also Delphi schon, aber Windows noch nicht. Nachdem ich Sleep von 1000 zwischen dem FindFirst....FindClose und der nächsten Prozedur, welche alle Verzeichnisse der Reihe nach entnehmend aus der StringListe löscht, geht es nun wunderbar.
Logikmensch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 390

Win XP
Delphi 2007 Prof., XE2, XE5
BeitragVerfasst: Do 18.10.07 05:24 
Uff. Sachen gibt's. Das wusste ich echt nicht. Aber ich hätte es mir auch denken können, dass es am Windows liegt, zumal ich auch mit dem Explorer oft auch das Problem habe, dass ich einen Ordner nicht löschen kann, selbst wenn er leer ist.
Wieder was dazugelernt. Hauptsache, es funzt.
Kannst den Code ja nochmal hier posten, dann haben wir alle was davon (ist auch für mich nicht uninteressant).

_________________
Es gibt keine Probleme - nur Lösungen!
LokutusvB Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 74

WinXP
Delphi 5, Delphi XE
BeitragVerfasst: Do 18.10.07 07:24 
Ist noch nicht ganz fertig, die Auswertung der Rückgabeparameter fehlt noch. Aber vielleicht findest du ja auch noch so Verbesserungsmöglichkeiten :)

ausblenden volle Höhe 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:
function TForm_Cleaner.leereOrdner(sStart: String): Boolean;
begin
  Result := True;
  slDir := TStringList.Create;
  findeOrdner(sStart);
  loescheOrdnerInhalt(sStart);
  sleep(500);
  loescheOrdner;
  FreeAndNil(slDir);
end;

procedure TForm_Cleaner.findeOrdner(sStart: String);
var
  srAkt: TSearchRec;
  sPfad: String;

begin
  sPfad := IncludeTrailingBackslash(sStart);
  if (FindFirst(sPfad + '*.*', faAnyFile, srAkt) = 0) then begin
    REPEAT
      if (((srAkt.Attr and faDirectory) = faDirectory)) then if ((srAkt.Name <> '.') and (srAkt.Name <> '..'))
        then begin
          slDir.Add(sPfad + srAkt.Name);
          findeOrdner(sPfad + srAkt.Name);
        end;
    UNTIL FindNext(srAkt) <> 0;
  end;
  FindClose(srAkt);
end;

function TForm_Cleaner.loescheOrdnerInhalt(sStart: String): Boolean;
var
  srAkt: TSearchRec;
  sTemp: String;
  ii: Integer;

begin
  Result := True;
  for ii := slDir.Count - 1 downto 0 do begin
    sTemp := IncludeTrailingBackslash(slDir.Strings[ii]);
    if (FindFirst(sTemp + '*.*', faAnyFile, srAkt) = 0) then begin
      REPEAT
        if (((srAkt.Attr and faDirectory) <> faDirectory)  and (srAkt.Name <> '.') and (srAkt.Name <> '..') and (srAkt.Attr <> faReadOnly))
          then try DeleteFile(sTemp + srAkt.Name); except Result := False; end;
      UNTIL FindNext(srAkt) <> 0;
    end;
    FindClose(srAkt);
  end;
  sTemp := IncludeTrailingBackslash(sStart);
  if (FindFirst(sTemp + '*.*', faAnyFile, srAkt) = 0) then begin
    REPEAT
      if (((srAkt.Attr and faDirectory) <> faDirectory)  and (srAkt.Name <> '.') and (srAkt.Name <> '..') and (srAkt.Attr <> faReadOnly))
        then try DeleteFile(sTemp + srAkt.Name); except Result := False; end;
    UNTIL FindNext(srAkt) <> 0;
  end;
  FindClose(srAkt);
end;

Function TForm_Cleaner.loescheOrdner: Boolean;
var
  sTemp: String;
  ii: Integer;

begin
  Result := True;
  for ii := slDir.Count -1  downto 0 do begin
    sTemp := slDir.Strings[ii];
    if (DirectoryIsEmpty(sTemp)) then begin
      try RmDir(sTemp); except Result := False; end;
    end;
  end;
end;