2 Stimmen

FindFirst, FindNext (Delphi Xe, Win7) Rang ist nicht korrekt

Ich habe einige Dateien in einem Verzeichnis. Ich versuche, diese Dateien mit FindFirst und FindNext zu erhalten, aber ich kann auf Windows 7 keine gleiche Reihenfolge erhalten.

C:\Test
SampleFile.0.png
SampleFile.1.png
SampleFile.2.png
SampleFile.3.png
SampleFile.4.png
SampleFile.5.png
SampleFile.6.png
SampleFile.7.png
SampleFile.8.png
SampleFile.9.png
SampleFile.10.png
SampleFile.11.png
SampleFile.12.png
SampleFile.13.png
SampleFile.14.png
SampleFile.15.png
SampleFile.16.png
SampleFile.17.png
SampleFile.18.png
SampleFile.19.png
SampleFile.20.png
SampleFile.21.png
SampleFile.22.png

Als ich versuchte, meinen Code zu verwenden, habe ich das bekommen

SampleFile.0.png
SampleFile.1.png
SampleFile.10.png
SampleFile.11.png
SampleFile.12.png
SampleFile.13.png
SampleFile.14.png
SampleFile.15.png
SampleFile.16.png
SampleFile.17.png
SampleFile.18.png
SampleFile.19.png
SampleFile.2.png
SampleFile.20.png
SampleFile.21.png
.
.
.

Wie kann ich die Dateiliste in der richtigen Rangfolge erhalten?

Prozedur Test;
var
sr : TSearchRec;
i : integer;
ListFiles : TStringList;  
begin
ListFiles := TStringList.Create;
i := FindFirst('c:\test\*.png', faDirectory, sr);
while i = 0 do begin  
ListFiles.Add(ExtractFileName(sr.FindData.cFileName));
i := FindNext(sr); 
end;
FindClose(sr);
end;  

Hinweis: Das Ergebnis ist immer noch falsch, auch wenn ich ListFiles.Sorted = True verwenden kann


Ich denke, ich habe eine Lösung gefunden, in dem ich eine Funktion erstellt habe.

function SortFilesByName(List: TStringList; Index1, Index2: Integer): integer;
var
FileName1, FileName2: String;
i, FileNumber1, FileNumber2: Integer;
begin
  FileName1 := ChangeFileExt(ExtractFileName(List[Index1]), '');
  FileName2 := ChangeFileExt(ExtractFileName(List[Index2]), '');
  i := POS('.', FileName1)+1;
  FileNumber1 := StrToInt(Copy(FileName1, i, MaxInt));
  i := POS('.', FileName2)+1;
  FileNumber2 := StrToInt(Copy(FileName2, i, MaxInt));
  Result := (FileNumber1 - FileNumber2);
end;

I've added another line ListFiles.CustomSort(SortFilesByName); //(ListFiles,1,2):integer); before FindClose(sr);

8voto

Zoë Peterson Punkte 12739

Wie von jachguate gesagt, wird die Sortierung von Explorer.exe und nicht vom Dateisystem durchgeführt. FindFirst/FindNext garantiert keine bestimmte Sortierung, einschließlich der reinen ASCII-basierten, daher sollten Sie sich nicht darauf verlassen. Sie müssen jedoch die numerische Sortierung nicht in Delphi neu implementieren. Windows zeigt die verwendete Sortierung durch StrCmpLogicalW an, die sich in shlwapi.dll befindet. Der Import sieht so aus:

function StrCmpLogicalW(psz1, psz2: PWideChar): Integer; stdcall;
  external 'shlwapi.dll'

Es ist möglich, dieses Verhalten in Windows zu deaktivieren. Wenn Sie die Reihenfolge beibehalten möchten, die Windows verwendet, müssen Sie SHRestricted mit dem Wert REST_NOSTRCMPLOGICAL aufrufen. Wenn es true zurückgibt, sollten Sie stattdessen AnsiCompareStr verwenden.

const
  // Verwenden Sie standardmäßig CompareString anstelle von StrCmpLogical
  REST_NOSTRCMPLOGICAL = $4000007E;

function SHRestricted(rest: DWORD): LongBool; stdcall; external 'shell32.dll';

Ihre endgültige Sortierfunktion sollte also etwas wie folgt aussehen:

function CompareFilenames(const AFilename1, AFilename2: string): Integer;
begin
  if SHRestricted(REST_NOSTRCMPLOGICAL) then
    Result := AnsiCompareStr(AFilename1, AFilename2)
  else
    Result := StrCmpLogicalW(PWideChar(AFilename1), PWideChar(AFilename2));
end;

Sie können das Ergebnis des SHRestricted-Aufrufs zwischenspeichern. Wenn Sie dies tun, müssen Sie jedoch auf die Broadcast-Nachricht WM_SETTINGSCHANGE achten und diese erneut lesen, wenn Sie eine erhalten.

1voto

jachguate Punkte 16748

Die verschiedenen Reihenfolgen, die Sie im Windows Explorer sehen, werden in explorer.exe implementiert und nicht im Dateisystem.

Die numerische Sortierreihenfolge ist eine neue Funktion in Windows 7, daher erkennt der Explorer, wenn Sie nach Name sortieren und eine Reihe von Dateien mit einem Präfix gefolgt von Zahlen haben, dieses Muster und präsentiert keine Liste, die auf herkömmliche Weise nach Namen sortiert ist, sondern nach Präfix und dann nach Zahl (als ob der String eine Integer-Zahl wäre).

Wenn Sie dasselbe in Delphi tun möchten, können Sie dies tun, indem Sie alle Dateinamen, die von FindFirst/FindNext zurückgegeben werden, zu einer TSlist hinzufügen und dann die Stringliste mit dieser Vergleichsfunktion sortieren:

var
  FileNames: TList;
begin
  FileNames := TList.Create;
  try
    SearchForFiles(FileNames); // hier fügen Sie alle Dateinamen hinzu
    // Dateinamen wie im Windows 7 Explorer sortieren
    FileNames.Sort(System.Generics.Defaults.TComparer.Construct(
      function (const s1, s2: string): Integer
        procedure ProcessPrefix(const fn: string; var prefix, number: string);
        var
          I: Integer;
        begin
          for I := Length(fn) downto 1 do
            if not TCharacter.IsDigit(fn[I]) then
            begin
              Prefix := Copy(fn, 1, I);
              Number := Copy(fn, I+1, MaxInt);
              Break;
            end;
        end;
      var
        Prefix1, Prefix2: string;
        Number1, Number2: string;
        Fn1, Fn2: string;
      begin
        // Dateinamen wie im Windows 7 Explorer vergleichen
        Fn1 := TPath.GetFileNameWithoutExtension(s1);
        Fn2 := TPath.GetFileNameWithoutExtension(s2);
        ProcessPrefix(Fn1, Prefix1, Number1);
        ProcessPrefix(Fn2, Prefix2, Number2);
        if (Number1 <> '') and (Number2 <> '') then
        begin
          Result := CompareText(Prefix1, Prefix2);
          if Result = 0 then
            Result := CompareValue(StrToInt(Number1), StrToInt(Number2));
        end
        else
          Result := CompareText(s1, s2);
      end
      ));
    UseYourSortedFileNames(FileNames);
  finally
    FileNames.Free;
  end;
end;

0voto

Ken White Punkte 120217

Bei "Rang" meinen Sie die Sortierreihenfolge.

Die Dateien werden in der richtigen Reihenfolge sortiert (basierend auf dem ASCII-Wert der Zeichen). 2 kommt nach 19, weil der Vergleich nur bis zur gleichen Anzahl von Zeichen in beiden Namen erfolgt und '2' nach 1 kommt.

Wenn Sie möchten, dass sie als Zahlen richtig sortiert werden, müssen Sie die Zahlen mit Nullen links auffüllen, damit sie alle die gleiche Breite haben (z.B. anstelle von SampleFile.2.png, verwenden Sie SampleFile.02.png). Dadurch kommt '02' vor 19, damit sie numerisch korrekt sortiert werden.

Sie können das Nummerierungsproblem beheben, indem Sie etwas Ähnliches verwenden:

PngDateiname := Format('SampleFile.%.2d.png', [Zähler]);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X