![]() |
Delphi-Version: XE7
Dateinamen auslesen und sortieren
Hallo zusammen,
ich finde einfach keine "einfache" Lösung für folgendes Problem. Ich möchte Dateinamen aus einem Ordner auslesen und sortieren. Dazu habe ich einen Ordner mit CSV-Dateien. Folgende Dateien sind enthalten:
Und genau in dieser Reihenfolge möchte ich die Dateien gern weiterverwenden. Ich habe nun versucht die Dateinamen einzulesen und per Add in eine TStringList zu schreiben. Dann rutscht die Datei 2.12.csv aber vor die 2.3.csv. Also habe ich die TStringList.Sorted auf True gesetzt. Das Ergebnis bleibt das gleiche. Ich habe mich jetzt auch schon mit TStringList.CustomSort beschäftigt. Da steige ich aber nicht so richtig dahinter. Außerdem scheint mir das auch relativ aufwendig. Das Ergebnis muss auch nicht zwangsläufig in eine TStringList. Ich will eben nur die Dateien in der gleichen Reihenfolge verarbeiten wie sie mir im Windows-Explorer angezeigt werden. Hat jemand eine Idee wie das geht? |
AW: Dateinamen auslesen und sortieren
Ist hier etwas für Dich dabei?
![]() |
AW: Dateinamen auslesen und sortieren
Ich habe es wie beschrieben mit der Funktion in Verbindung mit CustomSort versucht.
Delphi-Quellcode:
Leider bleibt das Ergebnis das gleiche.
CompareString(LOCALE_USER_DEFAULT, SORT_STRINGSORT or SORT_DIGITSASNUMBERS, PChar(S1),
Length(S1), PChar(S2), Length(S2)) - CSTR_EQUAL; |
AW: Dateinamen auslesen und sortieren
Habe es nur mal rasch mit FreePascal probiert und stelle nichts falsches fest wenn ich es so mache:
Code:
program Project1;
uses SysUtils, Classes; function CompareProc(List: TStringList; Index1, Index2: Integer): Integer; begin Result := string.Compare(List[Index1], List[Index2], [coIgnoreCase]); end; var SL: TStringList; i: Integer; begin SL := TStringList.Create; try SL.Add('2.6.1.csv'); SL.Add('4.5.csv'); SL.Add('4.9.1.csv'); SL.Add('1.3.csv'); SL.Add('2.3.csv'); SL.Add('2.6.2.csv'); SL.Add('1.7.csv'); SL.Add('4.9.2.csv'); SL.Add('1.6.csv'); SL.Add('2.8.csv'); SL.Add('2.6.3.csv'); SL.Add('4.8.csv'); SL.Add('2.12.csv'); SL.CustomSort(@CompareProc); for i := 0 to Pred(SL.Count) do WriteLn(SL[i]); finally SL.Free; end; ReadLn; end. Zitat:
|
AW: Dateinamen auslesen und sortieren
Bei Delphi klappt es mit folgender function:
Delphi-Quellcode:
function SortCompare(List: TStringList; Index1, Index2: Integer): Integer;
begin Result := string.Compare(List[Index1], List[Index2], [coDigitAsNumbers, coIgnoreCase]); end; |
AW: Dateinamen auslesen und sortieren
Danke für die Antworten.
Ich habe es jetzt mit beiden Versionen probiert. Allerdings ohne Erfolg... |
AW: Dateinamen auslesen und sortieren
Quelltext der Versionen, Fehlermeldungen, Dateiliste, Ergebnis? ...wir haben keine Glaskugel. :zwinker:
|
AW: Dateinamen auslesen und sortieren
doch :glaskugel:
sorry, musste sein Mal provieren die Punkte durch was anderes zu Replacen. Nicht dass die Dortiermethode denkt intelligent zu sein und den . als Dezimaltrennzeichen ansieht, denn 1.14 ist als "eine Zahl" wirklich kleiner, als 1.2 |
AW: Dateinamen auslesen und sortieren
Zitat:
|
AW: Dateinamen auslesen und sortieren
Zitat:
|
AW: Dateinamen auslesen und sortieren
Zitat:
|
AW: Dateinamen auslesen und sortieren
Es handelt sich aber nicht um Dezimalzahlen mit Nachkommastellen, sondern um Nummerierungen, wie sie z. B. auch bei Word, OpenOffice ... üblich sind.
Kapitel 2.3 steht da auch vor Kapitel 2.12, allerdings steht Kapitel 2.30 hinter Kapitel 2.12, ist aber nicht identisch mit Kapitel 2.3. Im vorliegenden Fall fehlt bei den Zahlen nach dem Punkt genaugenommen die führende 0 und die Sortierung soll die fehlende 0 mit berücksichtigen. Die Punkte sind letztlich nur optische Trenner zwischen unterschiedlichen Zahlengruppen. Jede Zahlengruppe soll für sich aufsteigend sortiert werden. Und damit ist 3 < 12 und von daher 2.3 vor 2.12 einzusortieren. |
AW: Dateinamen auslesen und sortieren
Hallo zusammen,
ja, also Delphi.Narium hat es richtig erfasst und zusammengefasst. Es handelt sich tatsächlich um eine Struktur wie bei einer Kapitelnummerierung. Und dort ist die 2.3 vor der 2.12 zu finden. Anfangs habe ich überhaupt nicht daran gedacht, dass es hier ein Problem geben könnte, da die Dateien im Explorer in der korrekten Reihenfolge angezeigt werden. Umso überraschter bin ich jetzt, dass es mir so schwer fällt dafür eine einfache Lösung zu finden. Gibt es denn irgendwo eine Übersicht über die möglichen "Filter" von TCompareOptions? Dann würde ich da gern weiterlesen um zu verstehen, wo es klemmt und wie es besser geht. |
AW: Dateinamen auslesen und sortieren
|
AW: Dateinamen auslesen und sortieren
Zitat:
|
AW: Dateinamen auslesen und sortieren
Kannst du vielleicht damit anfangen? Hier habe ich kurz ein Beispiel ohne string.compare gebastelt. Das funktioniert bei mir im Delphi 2007.
Delphi-Quellcode:
function MySortCompare(List: TStringList; Index1, Index2: Integer): Integer;
var wStr1: WideString; wStr2: WideString; Flags: Dword; begin wStr1 := List[Index1]; wStr2 := List[Index2]; Flags := 9; // coDigitAsNumbers + coIgnoreCase Result := CompareStringW(LOCALE_USER_DEFAULT, Flags, PWideChar(wStr1), Length(wStr1), PWideChar(wStr2), Length(wStr2)) - CSTR_EQUAL; end; procedure Tf_Tester.TestCustomSort; var SL: TStringList; i: Integer; begin m_test.Clear; SL := TStringList.Create; try SL.Add('2.6.1.csv'); SL.Add('4.5.csv'); SL.Add('4.9.1.csv'); SL.Add('1.3.csv'); SL.Add('2.3.csv'); SL.Add('2.6.2.csv'); SL.Add('1.7.csv'); SL.Add('4.9.2.csv'); SL.Add('1.6.csv'); SL.Add('2.8.csv'); SL.Add('2.6.3.csv'); SL.Add('4.8.csv'); SL.Add('2.12.csv'); SL.CustomSort(@MySortCompare); for i := 0 to Pred(SL.Count) do begin m_test.Lines.Add(SL[i]); end; finally FreeAndNil(SL); end; end; Zitat:
|
AW: Dateinamen auslesen und sortieren
Delphi-Quellcode:
Warum sinnlos einen langsamen und vor allem unnötigen Speichermanager benutzen, inkl. einiger unnötig aufwändiger/langsamer String-Operationen? (Strings komplett umkopieren)
function MySortCompare(List: TStringList; Index1, Index2: Integer): Integer;
var Str1, Str2: string; // oder direkt List[...] benutzen Flags: Dword; begin Str1 := List[Index1]; Str2 := List[Index2]; Flags := 9; // coDigitAsNumbers + coIgnoreCase Result := CompareString(LOCALE_USER_DEFAULT, Flags, PChar(Str1), Length(Str1), PChar(Str2), Length(Str2)) - CSTR_EQUAL; end; WideString = nutzt den Speichermanager, bzw. eine API des OLEAuth (OLE32) UnicodeString = die Wide-Version des AnsiString AnsiString/UnicodeString/UTF8String/usw. sind LongStrings und verwenden auch eine Referenzzählung, sowie den Delphi-Speichermanager (aktuell FastMM) PS: Der Typ String[123] ist ein ShortString (nur der Vollständigkeit halber) ... sowie der Typ "String" im Delphi 1 und davor im Turbo Pascal. |
AW: Dateinamen auslesen und sortieren
Zitat:
|
AW: Dateinamen auslesen und sortieren
Wie wäre es hiermit? Getestet mit Delphi Alexandria um eine "logische" Sortierung zu implementieren, dabei ist dann das "Kapitel" da wo es sein sollte.
Delphi-Quellcode:
program Project1;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Classes; function StrCmpLogicalW(P1, P2: PWideChar): Integer; stdcall; external 'Shlwapi.dll' name 'StrCmpLogicalW'; function CompareProc(List: TStringList; Index1, Index2: Integer): Integer; begin Result := StrCmpLogicalW(PChar(List[Index1]), PChar(List[Index2])); end; var SL: TStringList; i: Integer; begin try SL := TStringList.Create; try SL.Add('2.6.1.csv'); SL.Add('4.5.csv'); SL.Add('4.9.1.csv'); SL.Add('1.3.csv'); SL.Add('2.3.csv'); SL.Add('2.6.2.csv'); SL.Add('1.7.csv'); SL.Add('4.9.2.csv'); SL.Add('1.6.csv'); SL.Add('2.8.csv'); SL.Add('2.6.3.csv'); SL.Add('4.8.csv'); SL.Add('2.12.csv'); SL.CustomSort(@CompareProc); for i := 0 to Pred(SL.Count) do WriteLn(SL[i]); finally SL.Free; end; ReadLn; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. Zitat:
|
AW: Dateinamen auslesen und sortieren
Am Ende ist das doch alles das gleiche, oder was denkt ihr was die Delphi Methode intern macht?
Das Problem liegt offenbar woanders. |
AW: Dateinamen auslesen und sortieren
Hallo zusammen,
dann hier mal mein Code. Ich muss dazu sagen, dass ich an einem Rechner programmiere, der nicht mit dem Internet verbunden ist. Ich habe mir zwar beim Abschreiben Mühe gegeben, kann aber nicht ausschließen, dass sich ein Tipp-Fehler eingeschlichen hat.
Delphi-Quellcode:
function Sortierfunktion(Liste: TStringList; Index1: integer; Index2: integer): integer;
begin Result:=String.Compare(Liste[Index1],Liste[Index2],[coDigitAsNumbers,coIgnoreCase]); end; function AnlagenAuslesen: boolean; var Anlage: TSearchRec; DateiListe: TStringList; i: integer; begin Result:=true; DateiListe:=TStringList.Create; DateiListe.Sorted:=true; try if FindFirst(ExtractFilePath(ParamStr(0)),faAnyFile,Anlage)=0 then try begin //alle Dateien auslesen repeat if Anlage.Attr AND faDirectory=faDirectory then begin //nichts tun end else begin DateiListe.Add(Anlage.Name); end; until FindNext(Anlage)<>0; //Dateien sortieren DateiListe.CustomSort(@Sortierfunktion); //Dateien in der richtigen Reihenfolge auslesen i:=0; while not (DateiListe.Count=i) do begin DateiAuslesen(ExtractFilePath(ParamStr(0))+DateiListe[i]); //weitere Funktion zum Auslesen der Dateien i:=i+1; end; end; finally DateiListe.Free; FindClose(Anlage); end; except Result:=false; end; end; |
AW: Dateinamen auslesen und sortieren
DateiListe.Sorted:=true; <<--entfernen!
|
AW: Dateinamen auslesen und sortieren
Vielen herzlichen Dank auch an Uwe (ohne sein Drängen hätte ich mir wahrscheinlich nicht gleich die Mühe gemacht das Programm abzutippen)!
Jetzt klappt es. Diese Codezeile wurde in einem anderen Thread zu dem Thema als unbedingt notwendig betitelt. Und in euren Beispielen habe ich einfach übersehen, dass ihr sie weggelassen habt. VIELEN, VIELEN DANK noch einmal. Und entschuldigt, dass ihr euch wegen meiner Dusseligkeit so lange Gedanken dazu machen musstet. |
AW: Dateinamen auslesen und sortieren
Kommt drauf an
soll automatisch sortiert werden, dann ja, das muß, soll manuell sortiert werden, weil du hier selber CustomSort aufrufst, dann natürlich nicht. |
AW: Dateinamen auslesen und sortieren
Hmmm die Embarcadoro Hilfe für
![]() Zitat:
|
AW: Dateinamen auslesen und sortieren
Wäre
Delphi-Quellcode:
nicht einfacher?
if Anlage.Attr AND faDirectory <> faDirectory
Zudem gebe ich noch zu bedenken, dass du mit dem alleinigen Ausschluss von
Delphi-Quellcode:
sämtliche anderen Attribute (
faDirectory
Delphi-Quellcode:
) zulässt. Das mag in deinem Anwendungsfall keine Rolle spielen, sehr generisch ist es nicht.
(faReadOnly, faHidden, faSystem, faArchive,faDevice, faNormal, faTemporary, faSparseFile, faReparsePoint, faCompressed,faOffline, faNotContentIndexed, faEncrypted, faSymLink)
|
AW: Dateinamen auslesen und sortieren
Danke für den Hinweis.
Ich habe es jetzt mal beim FindFirst schon die Suche auf '*.csv' eingeschränkt. Damit hat sich das doch schon erledigt, oder? Sieht es jetzt besser aus?
Delphi-Quellcode:
if FindFirst(ExtractFilePath(ParamStr(0))+'*.csv',faAnyFile,Anlage)=0
then try begin //alle Dateien auslesen repeat if Anlage.Attr AND faDirectory<>faDirectory then DateiListe.Add(Anlage.Name); until FindNext(Anlage)<>0; usw.usf. |
AW: Dateinamen auslesen und sortieren
Am einfachsten wäre es vermutlich
![]() |
AW: Dateinamen auslesen und sortieren
So könnte es beispielsweise aussehen:
Delphi-Quellcode:
program Project1;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Classes, System.IOUtils, System.Types; function StrCmpLogicalW(P1, P2: PWideChar): Integer; stdcall; external 'Shlwapi.dll' name 'StrCmpLogicalW'; function CompareProc(List: TStringList; Index1, Index2: Integer): Integer; begin Result := StrCmpLogicalW(PChar(List[Index1]), PChar(List[Index2])); end; var SA: TStringDynArray; SL: TStringList; i: Integer; begin try SA := TDirectory.GetFiles(ExtractFilePath(ParamStr(0))); SL := TStringList.Create; try // mit oder ohne vollen Pfad? for i := Low(SA) to High(SA) do SL.Add(ExtractFileName(SA[i])); SL.CustomSort(@CompareProc); for i := 0 to Pred(SL.Count) do begin // mach was mit der Liste WriteLn(SL[i]); end; finally SL.Free; end; ReadLn; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. |
AW: Dateinamen auslesen und sortieren
Dann würde ich mir aber die TStringList sparen und direkt auf dem Array arbeiten:
Delphi-Quellcode:
program Project1;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.IOUtils, Generics.Collections, Generics.Defaults; function StrCmpLogicalW(P1, P2: PWideChar): Integer; stdcall; external 'Shlwapi.dll' name 'StrCmpLogicalW'; var i: Integer; SA: TArray<string>; begin try SA := TDirectory.GetFiles(ExtractFilePath(ParamStr(0))); TArray.Sort<string>(SA, TComparer<string>.Construct( function(const Left, Right : string) : Integer begin Result := StrCmpLogicalW(PWideChar(Left), PWideChar(Right)); end)); for i := 0 to High(SA) do begin // mach was mit der Liste WriteLn(SA[i]); end; ReadLn; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:13 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz