jaenicke
      
Beiträge: 19312
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 25.11.11 00:05
Hallo,
nach einer Frage im Forum habe ich einmal eine allgemeingültige Funktion zur Suche nach Dateien mit bestimmten Bedingungen erstellt. Diese ist explizit nicht für hohe Geschwindigkeit, sondern für viele Möglichkeiten gedacht. Dennoch ist die Geschwindigkeit denke ich hoch genug für die meisten Fälle.
Was ist möglich? - Suche nach einer oder mehreren Masken
- Ausschließen nach einer oder mehreren Masken
- Einschränken nach Minimaldatum und/oder Maximaldatum
- Suche nach Dateiattributen
- Suche in Unterordnern oder nur im angegebenen Ordner
- Callback für jeden durchsuchten Ordner als Statusanzeige
- Dateiliste mit:
- kompletten Pfaden
- oder relativen Pfaden
- oder nur mit den Dateinamen
Das ganze sieht dann so aus: 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:
| type TFileSearchOptions = set of (fsoRecursive, fsoRelativePaths, fsoOnlyFilenames); TSearchFilesCallback = reference to procedure(const ACurrentPath: string);
function PathCombine(lpszDest: PWideChar; const lpszDir, lpszFile: PWideChar): PWideChar; stdcall; external 'shlwapi.dll' name 'PathCombineW';
procedure GetAllFilesEx(AFileList: TStrings; const AParentPath, ASearchPath, AMasks: string; const AExcludes: string = ''; ASearchOptions: TFileSearchOptions = [fsoRecursive]; AAttributes: Integer = faAnyFile; ACallback: TSearchFilesCallback = nil; AMinAge: TDateTime = 0; AMaxAge: TDateTime = 2 * MAXWORD); var CompletePath, ParentPath, SearchPath, CurrentMask, CurrentFilename: string; Search: TSearchRec; MaskList, ExcludeList, ExcludedFiles: TStringList; begin if ASearchPath <> '' then SearchPath := IncludeTrailingPathDelimiter(ASearchPath) else SearchPath := ''; if AParentPath <> '' then ParentPath := IncludeTrailingPathDelimiter(AParentPath) else ParentPath := ''; SetLength(CompletePath, MAX_PATH); PathCombine(PChar(CompletePath), PChar(ParentPath), PChar(SearchPath)); SetLength(CompletePath, StrLen(PChar(CompletePath)));
if Assigned(ACallback) then ACallback(CompletePath);
ExcludedFiles := TStringList.Create; try ExcludeList := TStringList.Create; try ExcludeList.StrictDelimiter := True; ExcludeList.CommaText := AExcludes; for CurrentMask in ExcludeList do if FindFirst(CompletePath + CurrentMask, AAttributes, Search) = 0 then begin repeat ExcludedFiles.Add(AnsiUpperCase(CompletePath + Search.Name)); until FindNext(Search) <> 0; FindClose(Search); end; finally ExcludeList.Free; end;
MaskList := TStringList.Create; try MaskList.StrictDelimiter := True; MaskList.CommaText := AMasks; for CurrentMask in MaskList do if FindFirst(CompletePath + CurrentMask, AAttributes, Search) = 0 then begin repeat CurrentFilename := CompletePath + Search.Name; if (ExcludedFiles.IndexOf(AnsiUpperCase(CurrentFilename)) < 0) and (Search.TimeStamp >= AMinAge) and (Search.TimeStamp <= AMaxAge) then begin if fsoRelativePaths in ASearchOptions then AFileList.Add(ExtractRelativePath(ParentPath, CurrentFilename)) else if fsoOnlyFilenames in ASearchOptions then AFileList.Add(Search.Name) else AFileList.Add(CurrentFilename); end; until FindNext(Search) <> 0; FindClose(Search); end; finally MaskList.Free; end; finally ExcludedFiles.Free; end;
if fsoRecursive in ASearchOptions then begin if FindFirst(CompletePath + '*.*', faDirectory, Search) = 0 then begin repeat if ((Search.Attr and faDirectory) = faDirectory) and (Search.Name[1] <> '.') then GetAllFilesEx(AFileList, AParentPath, SearchPath + Search.Name, AMasks, AExcludes, ASearchOptions, AAttributes, ACallback, AMinAge, AMaxAge); until FindNext(Search) <> 0; FindClose(Search); end; end; end; | Die Trennung in AParentPath und ASearchPath dient dazu, dass die Dateinamen relativ zu dem Hauptordner in AParentPath zurückgegeben werden können. Im zweiten Beispiel wird zwar unterhalb von C:\Program Files (x86)\Embarcadero\RAD Studio gesucht, aber "RAD Studio" ist in den Dateipfaden enthalten.
Ein kurzer Beispielaufruf, nur mit mehreren Masken: Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| var FileList: TStringList; begin FileList := TStringList.Create; try GetAllFilesEx(FileList, 'C:\Program Files (x86)\Embarcadero', '', '*.exe,*.txt'); ShowMessage(FileList.Text); finally FileList.Free; end; end; |
Und ein ausführlicher Beispielaufruf sieht dann so aus, wobei der aktuelle Ordner als Status in die Caption des Formulars geschrieben wird: Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| var FileList: TStringList; begin FileList := TStringList.Create; try GetAllFilesEx(FileList, 'C:\Program Files (x86)\Embarcadero', 'RAD Studio', '*.exe,*.txt', 'bds.exe,g*', [fsoRecursive, fsoRelativePaths], faAnyFile, procedure(const ACurrentPath: string) begin Caption := ACurrentPath; end); ShowMessage(FileList.Text); finally FileList.Free; end; end; | Hier werden alle .exe oder .txt Dateien gesucht, wobei bds.exe und alle mit g beginnenden Dateien ausgeschlossen werden.
Die Funktion ist in der jetzigen Form ausschließlich mit Delphi XE und höher verwendbar. Für Delphi 2010 oder früher sind Anpassungen erforderlich (bei Delphi 2010 gibt es noch kein TimeStamp in TSearchRec und vor Delphi 2006 gibt es noch keine for..in Schleife). Ich denke aber der Sinn sollte klar werden, bei Bedarf könnt ihr euch das ja anpassen.
Weitere bereits vorhandene Varianten für eine Dateisuche von anderen Membern:
www.delphi-library.d...en+suchen_21275.html
www.delphi-library.d...issen+suchen_94.html
www.delphi-library.d...tsanzeige_47880.html
www.delphi-library.d...tVariante_15203.html
www.delphi-library.d...ien+suchen_1107.html
Viel Spaß damit
Schönen Gruß,
Sebastian
|