Dateisuche mit Fortschrittsanzeige
Endlich ist sie da, die langersehnte Dateisuche mit Fortschrittsanzeige.
Erstmal der Code, dann die Erklärungen.
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; FFM_ONDIRFOUND = WM_USER + 1975; var CntFolders : Cardinal = 0; NumFolder : Cardinal = 0;
procedure FindAllFilesInit; begin CntFolders := 0; NumFolder := 0; end;
procedure CountFolders(Handle: THandle; RootFolder: string; Recurse: Boolean = True); var hFindFile : THandle; wfd : TWin32FindData; begin SendMessage(Handle, FFM_INIT, 0, 0); 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;
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:
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 delfiphan: Beitragsformatierung überarbeitet.
Moderiert von jasocul: Beitrag geprüft am 09.06.2006