AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Schnelle Methode, um eine Dateiliste zu erstellen

Ein Thema von DieDolly · begonnen am 23. Feb 2021 · letzter Beitrag vom 24. Feb 2021
Antwort Antwort
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#1

Schnelle Methode, um eine Dateiliste zu erstellen

  Alt 23. Feb 2021, 11:59
Vielleicht erst ein kleiner Hintergrund.
Ich habe früher mal anhand zweiter StringListen, die gefüllt sein können aber nicht müssen, eine weitere Liste erstellen lassen (eine Dateiliste).
Die eine StringListe enthielt (kann, muss nicht) Pfade, die unbedingt vom Such-Algorithmus (bei mir damals FindFirst, FindNext) in der neuen Dateiliste aufgenommen werden sollen. Die zweite StringListe enthielt Pfade, die in keinem Fall in der Dateiliste aufgenommen werden sollen.

Beispiele:
- war die erste StringListe gefüllt, wurden auch nur diese Pfade in der neuen Dateiliste aufgenommen.
- war die zweite gefüllt, wurden alle außer die in der Liste in die Dateiliste aufgenommen.

Basierend auf einem Verzeichnis "E:\": diese StringListen können beispielsweise enthalten
- Dateien
- Arbeit
- Freizeit\Fotos

Im o.g. Beispiel würden nur die Verzeichnisse "Dateien", "Arbeit" und "Freizeit\Fotos" in die neue Dateiliste übernommen (erste Liste)
ODER
alle außer genau die oben genannten (zweite Liste).


Meine vorgehensweise damals war in etwa so:
- FindFirst/FindNext-Procedure (in sich selbst aufrufend, wegen der Unterverzeichnisse)
-- jede Datei, jedes Verzeichnis das gefunden wird durch eine Funktion laufen lassen, die eine Schleife durchläuft und die StringListe prüft.
Und irgendwie habe ich beide Listen in das ganze Ding reingepackt mit if's und else's und viel zu kompliziert.


Wie realisiert man sowas mit D10.3.3 am besten? Ich habe leider keinen Code mehr davon. Ich weiß nur noch, dass das mit StringListen-Abgleich mindestens um den Faktor 10 langsamer war als ohne.

Geändert von DieDolly (23. Feb 2021 um 12:09 Uhr)
  Mit Zitat antworten Zitat
TurboMagic

Registriert seit: 28. Feb 2016
Ort: Nordost Baden-Württemberg
2.838 Beiträge
 
Delphi 12 Athens
 
#2

AW: Schnelle Methode, um eine Dateiliste zu erstellen

  Alt 23. Feb 2021, 17:05
Naja, du könntest mal anschauen was IOUtils so alles bietet.
Zum Beispiel TPath...
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.034 Beiträge
 
Delphi 12 Athens
 
#3

AW: Schnelle Methode, um eine Dateiliste zu erstellen

  Alt 23. Feb 2021, 21:27
Die Anforderungen sind aber noch nicht vollständig definiert, oder?

Was soll passieren, wenn beide Listen gefüllt sind?
Welche Liste hat Vorrang, wenn die Listen sich widersprechen?
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#4

AW: Schnelle Methode, um eine Dateiliste zu erstellen

  Alt 23. Feb 2021, 23:17
Zitat:
Was soll passieren, wenn beide Listen gefüllt sind?
Beide Listen können nie zeitgleich gefüllt sein.

Ist die erste Liste gefüllt, wird die zweite gar nicht erst befüllt und kann ignoriert werden.
Wie das andersherum aussieht, muss ich noch überlegen.

Die erste Liste soll ausschließlich ihre Einträge vergleichen und Funde in eine Dateiliste schreiben.
Die zweite Liste soll ihre Einträge vergleichen und Funde sollen nicht zur Dateiliste hinzugefügt werden.

Geändert von DieDolly (23. Feb 2021 um 23:20 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.685 Beiträge
 
Delphi 11 Alexandria
 
#5

AW: Schnelle Methode, um eine Dateiliste zu erstellen

  Alt 24. Feb 2021, 00:33
Das mit den verschiedenen Listen habe ich noch nicht so ganz verstanden, jedenfalls finde ich die schnellste Methode es über PItemIdList zu Lösen. Es ist gleichzeitig nicht die einfachste Möglichkeit da mehr Code benötigt wird.

In der Paxis kannst Du es testen indem Du mal TotalCommander (Shareware Datei-Manager) installierst und in ein Verzeichnis mit Tausenden von Dateien lotst.
Gegenüber FindFirst() ist das der Ferrari

In Kombination mit einem Verzeichnis-Monitor wirst du eventuell gar keine zwei Listen benötigen sondern einfach PIDLs sich selbst aktualisieren lassen.

Es gab mal eine VirtualShellView Demo von Borland um sich damit anzufreunden.

Vielleicht liege ich auch total daneben, dann tut es mir leid.
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#6

AW: Schnelle Methode, um eine Dateiliste zu erstellen

  Alt 24. Feb 2021, 07:25
Das mit den verschiedenen Listen habe ich noch nicht so ganz verstanden
Halb-zitiert von mir:
Diese StringListen können beispielsweise nach einer Eingabe diesen Inhalt haben
- Dateien
- Arbeit
- Freizeit\Fotos

Wenn das da oben in der ersten Liste steht: nur die Verzeichnisse "Dateien", "Arbeit" und "Freizeit\Fotos" würden in die neue Dateiliste übernommen
ODER
wenn das in der zweiten Liste streht: alle außer genau die oben genannten werden in die neu Dateiliste übernommen.

Also quasi "Füge nur diese Dateien (wenn gefunden) in die Dateiliste ein (erste Liste)
oder
füge alle Dateien außer die oben (wenn gefunden) in die Dateiliste ein (zweite Liste).
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.034 Beiträge
 
Delphi 12 Athens
 
#7

AW: Schnelle Methode, um eine Dateiliste zu erstellen

  Alt 24. Feb 2021, 13:13
Wenn ich also mal das Beispiel deines Eingangsposts nehme:

Zitat:
Basierend auf einem Verzeichnis "E:\": diese StringListen können beispielsweise enthalten
- Dateien
- Arbeit
- Freizeit\Fotos
Dann könnte man die Liste so aussehen:
Zitat:
Dateien
Arbeit
Freizeit\Fotos
*.jpg
*.bmp
und das würde dann alle jpg- und bmp-Dateien in den drei genannten Verzeichnissen samt ihrer Unterverzeichnisse aufgelistet?
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#8

AW: Schnelle Methode, um eine Dateiliste zu erstellen

  Alt 24. Feb 2021, 13:17
Das ist jetzt eine gute Frage.
Vielleicht eher so, damit die Wildcards ans Verzeichnis gebunden sind

Zitat:
Dateien
Arbeit
Freizeit\Fotos\*.jpg
Dateien, Arbeit: das komplette Verzeichnis wird verarbeitet
Freizeit\Fotos\*.jpg: nur jpg-Dateien in Freizeit\Fotos.

So könnte das auch aussehen (Dateien: nur pas-Dateien, Arbeit: komplett, Freizeit\Fotos komplett)
Zitat:
Dateien\*.pas
Arbeit
Freizeit\Fotos
Oder so (Dateien, Arbeit und Freizeit\Fotos: komplett)
Zitat:
Dateien
Arbeit
Freizeit\Fotos

Oder so (Dateien, Arbeit und Freizeit\Fotos: das würde mit PathMatchSpecW nur Dateien durchlassen, die mit "img" anfangen, danach "ein beliebiger Buchstabe oder Zahl")
Zitat:
Dateien
Arbeit
Freizeit\Fotos\img?.txt

Geändert von DieDolly (24. Feb 2021 um 13:21 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.034 Beiträge
 
Delphi 12 Athens
 
#9

AW: Schnelle Methode, um eine Dateiliste zu erstellen

  Alt 24. Feb 2021, 13:59
Bei dem Exclude-Fall müsste man unterscheiden, ob lediglich ein Verzeichnis angegeben ist oder ein Verzeichnis mit Wildcards. Im ersten Fall kann man das Verzeichnis überspringen (das macht mein erster Vorschlag), aber im zweiten Fall muss das Verzeichnis gescannt und die entsprechenden Einträge ausgefiltert werden.

Um das besser kontrollieren zu können, würde ich die LstExclude in zwei Listen LstExcludeDirs und LstExcludeFiles aufsplitten. Hier nochmal ein etwas komplexerer Ansatz (mit kleiner Optimierung beim Checken der Excludes) - ungetestet:
Delphi-Quellcode:
procedure ListFiles(const Root: string; LstInclude, LstExclude, Target: TStrings);

  function Matches(const Value: String; const Arr: TArray<string>): Boolean;
  var
    foundIndex: Integer;
  begin
    Result := TArray.BinarySearch<string>(Arr, Value, foundIndex, TIStringComparer.Ordinal);
    if not Result and (foundIndex > 0) then
      Result := Value.StartsWith(Arr[foundIndex-1], True);
  end;

var
  arr: TArray<string>;
  lstExcludeDirs: TStringList;
  lstExcludeFiles: TStringList;
  mask: string;
  path: string;
  S: string;
begin
  if (LstInclude <> nil) and (LstInclude.Count > 0) then begin { Includes vorhanden? }
    for S in LstInclude do begin
      path := TPath.Combine(Root, S);
      mask := '*.*';
      if path.Contains('*') or path.Contains('?') then begin
        mask := TPath.GetFileName(path);
        path := TPath.GetDirectoryName(path);
      end;
      Target.AddStrings(TDirectory.GetFiles(path, mask, TSearchOption.soAllDirectories));
    end;
  end
  else if (LstExclude <> nil) and (LstExclude.Count > 0) then begin { Excludes vorhanden? }
    lstExcludeDirs := TStringList.Create;
    try
      lstExcludeFiles := TStringList.Create;
      try
        for S in LstExclude do begin
          path := S;
          if path.Contains('*') or path.Contains('?') then begin
            LstExcludeFiles.Add(path);
            { damit der Pfad erstmal excluded wird, tragen wir ihn auch in die andere Liste ein }
            path := TPath.GetDirectoryName(path);
          end;
          LstExcludeDirs.Add(path);
        end;

        { Erst arbeiten wir die ganzen Pfade ab und überspringen die Excluded Pfade }
        { Für bessere Performance sortieren wir die Excludes einmal, damit wir in Matches das BinarySearch verwenden können }
        arr := LstExcludeDirs.ToStringArray;
        TArray.Sort<string>(arr, TIStringComparer.Ordinal);

        for path in TDirectory.GetDirectories(Root, '*', TSearchOption.soAllDirectories) do begin
          { ist es ein Exclude Path? }
          if not Matches(path, arr) then
            Target.AddStrings(TDirectory.GetFiles(path, '*.*', TSearchOption.soTopDirectoryOnly));
        end;

        { nun noch die excluded Paths mit den Wildcard-Einträgen }
        for S in lstExcludeFiles do begin
          mask := TPath.GetFileName(S);
          path := TPath.GetDirectoryName(S);
          Target.AddStrings(TDirectory.GetFiles(path, '*.*', TSearchOption.soAllDirectories,
            function(const Path: string; const SearchRec: TSearchRec): Boolean
            begin
              Result := TPath.MatchesPattern(SearchRec.Name, mask, False);
            end
            ));
        end;
      finally
        lstExcludeFiles.Free;
      end;
    finally
      lstExcludeDirs.Free;
    end;
  end
  else begin { keine Einschränkungen }
    Target.AddStrings(TDirectory.GetFiles(Root, '*.*', TSearchOption.soAllDirectories));
  end;
end;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#10

AW: Schnelle Methode, um eine Dateiliste zu erstellen

  Alt 24. Feb 2021, 14:25
Ist TDirectory.GetFiles und TPath das moderne FindFirst FindNext?
Ich habe um alle aufrufe Target.AddStrings noch ein TDirectory.Exists(path) gesetzt, damit es nicht zu Fehlern kommt wenn es da was nicht gibt (Garbage in, Garbage out: falsche Parameter die man übergibt oder so).

Meine testfälle scheinen alle zu funktionieren, was LstInclude angeht. LstExlude muss ich noch testen aber ich denke, das funktioniert alles.

Ok einen Fall hab ich das funktioniert nicht. Man kann keine Dateien mehr in die Listen schreiben.
Deswegen habe ich etwas umgeändert
Delphi-Quellcode:
// statt
Target.AddStrings(TDirectory.GetFiles(path, mask, SearchOption));

// jetzt
     if IsDirectory(path) then
      begin
       if TDirectory.Exists(path) then
        Target.AddStrings(TDirectory.GetFiles(path, mask, SearchOption));
      end
     else
      Target.Add(path);
Aber irgendwas stimmt auch nicht. Deswegen habe ich noch weiter rumprobiert ohne zu wissen was ich wirklich mache. Aber jetzt scheint es zu funktionieren mit beiden Listen.
EINE Sache funktioniert aber noch immer nicht.

LstInclude.Add('*.txt');
ListFiles('P:\Audacity Portable', LstInclude, LstExclude, sl, True);

Hier denke ich, dass nur Txt-Dateien i, Root von ListFiles eingeschlossen werden sollen. Es werden aber alle in allen Unterverzeichnissen übernommen.
Ich probiere noch weiter rum irgendwann werde ich eine Lösung haben.
Bis ich die habe, habe ich den Code hier unten erstmal wieder gelöscht.

Geändert von DieDolly (24. Feb 2021 um 17:08 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:58 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz