Autor Beitrag
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 06.09.05 08:14 
Dateisuche mit Fortschrittsanzeige
Endlich ist sie da, die langersehnte Dateisuche mit Fortschrittsanzeige. ;)

Erstmal der Code, dann die Erklärungen.

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:
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:
105:
106:
107:
108:
uses Windows, Messages;

const
  FFM_INIT               = WM_USER + 1976;
  FFM_ONFILEFOUND        = WM_USER + 1974// wParam: not used, lParam: Filename
  FFM_ONDIRFOUND         = WM_USER + 1975// wParam: NumFolder, lParam: Directory

var
  CntFolders             : Cardinal = 0;
  NumFolder              : Cardinal = 0;


////////////////////////////////////////////////////////////////////////////////
//
//  FindAllFilesInit
//
//

procedure FindAllFilesInit;
begin
  CntFolders := 0;
  NumFolder := 0;
end;

////////////////////////////////////////////////////////////////////////////////
//
//  CountFolders
//
//

procedure CountFolders(Handle: THandle; RootFolder: string; Recurse: Boolean = True);
var
  hFindFile              : THandle;
  wfd                    : TWin32FindData;
begin
  SendMessage(Handle, FFM_INIT, 00);
  if RootFolder[length(RootFolder)] <> '\' then
    RootFolder := RootFolder + '\';
  ZeroMemory(@wfd, sizeof(wfd));
  wfd.dwFileAttributes := FILE_ATTRIBUTE_NORMAL;
  if Recurse then
  begin
    hFindFile := FindFirstFile(pointer(RootFolder + '*.*'), wfd);
    if hFindFile <> 0 then
    try
      repeat
        if wfd.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY = FILE_ATTRIBUTE_DIRECTORY then
        begin
          if (string(wfd.cFileName) <> '.'and (string(wfd.cFileName) <> '..'then
          begin
            CountFolders(Handle, RootFolder + wfd.cFileName, Recurse);
          end;
        end;
      until FindNextFile(hFindFile, wfd) = False;
      Inc(CntFolders);
    finally
      Windows.FindClose(hFindFile);
    end;
  end;
end;

////////////////////////////////////////////////////////////////////////////////
//
//  FindAllFiles
//

procedure FindAllFiles(Handle: THandle; RootFolder: string; Mask: string; Recurse: Boolean = True);
var
  hFindFile              : THandle;
  wfd                    : TWin32FindData;
begin
  if RootFolder[length(RootFolder)] <> '\' then
    RootFolder := RootFolder + '\';
  ZeroMemory(@wfd, sizeof(wfd));
  wfd.dwFileAttributes := FILE_ATTRIBUTE_NORMAL;
  if Recurse then
  begin
    hFindFile := FindFirstFile(pointer(RootFolder + '*.*'), wfd);
    if hFindFile <> 0 then
    try
      repeat
        if wfd.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY = FILE_ATTRIBUTE_DIRECTORY then
        begin
          if (string(wfd.cFileName) <> '.'and (string(wfd.cFileName) <> '..'then
          begin
            FindAllFiles(Handle, RootFolder + wfd.cFileName, Mask, Recurse);
          end;
        end;
      until FindNextFile(hFindFile, wfd) = False;
      Inc(NumFolder);
      SendMessage(Handle, FFM_ONDIRFOUND, NumFolder, lParam(string(RootFolder)));
    finally
      Windows.FindClose(hFindFile);
    end;
  end;
  hFindFile := FindFirstFile(pointer(RootFolder + Mask), wfd);
  if hFindFile <> INVALID_HANDLE_VALUE then
  try
    repeat
      if (wfd.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> FILE_ATTRIBUTE_DIRECTORY) then
      begin
        SendMessage(Handle, FFM_ONFILEFOUND, 0, lParam(string(RootFolder + wfd.cFileName)));
      end;
    until FindNextFile(hFindFile, wfd) = False;
  finally
    Windows.FindClose(hFindFile);
  end;
end;

Demo:
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:
procedure TForm1.WndProc(var Msg: TMessage);
begin
  inherited;
  case Msg.Msg of
    FFM_INIT:
    begin
      Label1.Caption := 'Initialisiere..';
      Form1.Refresh;
    end;
    FFM_ONFILEFOUND:
    begin
      ListBox1.Items.Add(PChar(Msg.LParam));
      Label1.Caption := PChar(Msg.LParam);
      Form1.Refresh;
    end;
    FFM_ONDIRFOUND:
    begin
      Progressbar1.Position := Msg.WParam;
      Label1.Caption := PChar(Msg.LParam);
      Form1.Refresh;
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Listbox1.Clear;
  FindAllFilesInit;
  CountFolders(Handle, 'd:\', true);
  Progressbar1.Max := CntFolders;
  FindAllFiles(Handle, 'd:\''*.*', true);
end;

Erstmal zur Prozedur FindAllFiles: Ich wollte möglichst ohne die Unit Classes auskommen und habe mich deshalb entschieden die Dateien nicht ine eine StringListe zu schreiben, sondern eine Nachricht zu schicken, welche den Dateinamen bzw. den Ordner und den wievielten Ordner enthält.

Die Idee: Will man den Fortschritt anzeigen, muss man irgendwie einen maximal Wet haben. Ich habe mich dafür entschieden die Anzahl der Ordner zu nehmen. Die Anzahl der Ordner wird mit der Prozedur CountFolders ermittelt und in der globalen Variable CntFolders gespeichert. In der Prozedur FindAllFiles wird nun bei jedem gefundenen Ordner die Variavle NumFolder erhöht, damit man weiß, wie viele Ordner man schon durchsucht hat.

Da ich mit globalen Variablen arbeite, ist es wichtig diese entsprechend zu initialisieren. Dies geschieht mit der Prozedur FindAllFilesInit. Hier werden die Variablen mit 0 initialisiert. Es ist also erstmal wichtig diese Prozedur aufzurufen und dann mit CountFolders die Anzahl der Ordner zu ermitteln, wenn man einen Fortschritt haben will. Durchsucht man nicht gerade die ganze Systempartition, ist der Performanceverlust eigentlich noch akzeptabel. Natürlich kann man die Prozedur FindAllFiles auch nutzen ohne den Fortschritt anzuzeigen, wenn man auf die Performance wertlegt.

Legt man keinen Wert darauf nonVCL kompatibel zu sein, kann man natürlich alles in eine Klasse packen und elegant mit Eregnisse arbeiten.

Auf die Idee bin ich gekommen, als ich mich gefargt habe, wie TuneupUtilities das macht und ich gesehen habe, wie Tuneup Utilities vor der eigentlichen Suche in einem Label "Initialisieren..." anzeigt. da habe ich mich gefagt, "was macht initialisiert der da wohl?" Nun ja, ich habe mir dann überlegt, dass er eigentlich nur einen maximal Wert für den Fortschritt ermitteln kann in dieser Zeit.

Sollte jemand eine bessere Idee haben, dann bin ich für jeden Verbesserungsvorschlag offen.

Moderiert von user profile icondelfiphan: Beitragsformatierung überarbeitet.
Moderiert von user profile iconjasocul: Beitrag geprüft am 09.06.2006