0

Possible Duplicate:
How to get the sort order in Delphi as in Windows Explorer?

I am trying to scan a directory, but I can't get it to Sort by File Name.

Example, say if I have these Filenames in a folder:

  • File1
  • File2
  • File3
  • File4
  • File5
  • File6
  • File7
  • File8
  • File9
  • File10
  • File11
  • File12
  • File13
  • File14
  • File15
  • File16
  • File17
  • File18
  • File19
  • File20
  • File21
  • File22

If I use something like this:

var
  SL: TStringList;
  SR: TSearchRec;  
begin
  SL := TStringList.Create;
  try
    if FindFirst(Path + '*.*', faAnyFile and not faDirectory and not faHidden, SR) = 0 then
    repeat
      SL.Add(Path + SR.Name)
    until FindNext(SR) <> 0;

    FindClose(SR);

    // handle the filenames..
  finally
    SL.Free;
  end;
end;

The result will be:

  • File10
  • File11
  • File12
  • File13
  • File14
  • File15
  • File16
  • File17
  • File18
  • File19
  • File2
  • File20
  • File21
  • File22
  • File3
  • File4
  • File5
  • File6
  • File7
  • File8
  • File9

It should be sorted by Filename (as I wrote in the first Filename list example).

I bet this is really simple but I cannot see it, what do I need to do to sort this?

Thanks.

Community
  • 1
  • 1

3 Answers3

8

You're starting with the assumption that there's some sort of inherent "order" for file names. There isn't. You appear to want the file names to be sorted alphabetically, with numerical portions of names sorted numerically. I'm not sure what you want to happen with punctuation and other characters.

The file-enumeration functions don't define any order that names will be returned in. They're returned in whatever order the underlying file system decides to provide them. There are two steps to getting a sorted list of file names. You're already doing the first one:

  1. Collect the file names in a list for post-processing.

  2. Arrange the names in the order you want. If plain "asciibetical" isn't what you want, then you can write a custom sorting function and pass it to TStringList.CustomSort.

For example, if you want them to be in the same order you see file names in Windows Explorer as of Windows XP, you can use the StrCmpLogicalW API function. Call that from your comparison function, like this:

function LogicalCompare(List: TStringList; Index1, Index2: Integer): Integer;
begin
  Result := StrCmpLogicalW(PWideChar(List[Index1]), PWideChar(List[Index2]));
end;

SL.CustomSort(LogicalCompare);

If you have something earlier than Delphi 2007, you'll need to do something about converting your strings to wide characters, at least for the duration of the sorting phase.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • Interestingly the Windows 7 Explorer implements exactly this order when you sort by name. – Uwe Raabe Dec 28 '11 at 22:16
  • Exactly *which* order, @Uwe? There are two orders demonstrated in Craig's question. – Rob Kennedy Dec 28 '11 at 22:19
  • The order he tries to acomplish: ...File9, File10... – Uwe Raabe Dec 28 '11 at 22:21
  • I found an article describing this behaviour: [http://support.microsoft.com/kb/319827/en-us](http://support.microsoft.com/kb/319827/en-us) – Uwe Raabe Dec 28 '11 at 22:22
  • I am using Windows 7 and Delphi XE, the order I wanted does not show like that Uwe. Thanks for your answer Rob, I now understand that I need to handle this behaviour myself (I thought Sorted := True would of worked!).... I found a related question here which seems to expand on what Rob said about the StrCmpLogicalW > http://stackoverflow.com/questions/5134712/how-to-get-the-sort-order-in-delphi-as-in-windows-explorer –  Dec 28 '11 at 22:23
  • @Uwe, Windows Explorer has been showing files in that order since Windows XP. That Windows 7 still does it that way doesn't seem very interesting to me. – Rob Kennedy Dec 28 '11 at 22:27
  • Actually, on NTFS volumes there is an inherent sort order. Files will always be returned in alphabetical order (which is what the OP got). But always keep in mind, that this does not apply to FAT or network file systems (e.g. on a SAMBA server). Windows Explorer got changed in some SP to XP to allow for numerical sorting in the display like the OP wants but that's an Explorer function not one of the Windows API. – dummzeuch Dec 29 '11 at 09:21
  • @Dummzeuch, the NTFS order is not alphabetical. It's more akin to a case-insensitive "asciibetical" sort. If I show you two file names and you need to ask me which file system they're stored on before you tell me which comes first, then the order is not an inherent property of the names themselves. – Rob Kennedy Dec 29 '11 at 15:47
3

FindFirst() and FindNext() merely enumerate the files on the file system as-is. The files can be returned in any order. You have to sort the TStringList yourself afterwards, eg:

function SortFilesByName(List: TStringList; Index1, Index2: Integer): Integer;
var
  FileName1, FileName2: String;
  FileNumber1, FileNumber2: Integer;
begin
  // assuming the files are all named "Path\File###.xxx",
  // where "###" is the number to sort on...
  FileName1 := ChangeFileExt(ExtractFileName(List[Index1]), '');
  FileName2 := ChangeFileExt(ExtractFileName(List[Index1]), '');
  FileNumber1 := StrToInt(Copy(FileName1, 5, MaxInt));
  FileNumber2 := StrToInt(Copy(FileName2, 5, MaxInt));
  Result := (FileNumber2 - FileNumber1);
end;

var 
  SL: TStringList; 
  SR: TSearchRec;   
begin 
  SL := TStringList.Create; 
  try 
    if FindFirst(Path + '*.*', faAnyFile and (not faDirectory) and (not faHidden), SR) = 0 then 
    try
      repeat 
        SL.Add(Path + SR.Name) 
      until FindNext(SR) <> 0; 
    finally
      FindClose(SR); 
    end;

    SL.CustomSort(SortFilesByName);
    // handle the filenames.. 
  finally 
    SL.Free; 
  end; 
end; 
Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

Any simple sort system (such as the one windows uses to return you files and delphi uses for sorting) will sort alphabetically and then by number, but unless you pad your numbers with zeros

  • 1 comes before 2 so
  • 11 comes before 2 (in the same way that aa comes before b)

you either need to pad you numbers with zeros such as

  • filename001
  • filename010
  • filename020

for use the answer provided by Remy Lebeau - TeamB above which will pull out the number at the end of you filename and sort by that.

Toby Allen
  • 10,997
  • 11
  • 73
  • 124