Folderitem Directory Sort

Hi all!

I’m reading a directory…something like:

for i as integer = 1 to f.count
    tmp file = f.item(i).name

I’m curious, in that the names of the files were in alphabetical order at one point. Now, it looks like the files are not. What happened?
How do I get it to deliver the files in alphabetical order?

I know I read into an array and then sort, but it’s not something I had to do before.


The order is not guaranteed.

MacOS used to return them sorted, but that is not done for APFS.
But you can put them in an array as well as their names and use Array.SortWith function.

Got it. Thanks!

Now that APFS returns items in unexpected order, recursion (either using a loop or by calling the same method (not recommended)) leads to weird results.
1: when showing the path to the currently iterated folder, the user can no longer “approximately determine” the progress. In alphabetical order, you could think “/Applications” is near the start and “/Users” is near the end, so you could guess the remaining time.
2: in my specific case, I search for files inside a given folder; in order to avoid looking in big folders, since the app cannot predict the number of items in a given folder, my solution is to have a folder “.Do not look here”, manually created in those huge folders. With the disorder made by APFS, I can’t assume this will be the first discovered folder, so my app may just list the whole folder before knowing it shouldn’t have to, by finally encountering the “.Do not look here” folder. I end up checking the folder’s existence using .Child(".Do not look here") but I expect it would be slower (for every iterated folder in which my “.Do not look here” folder isn’t existing, I must check for its existence).

I use a loop to list the whole folder (using arrays for folders and indexes). While sorting folders alphabetically would be easy for a single folder (using SortWith and 2 loops), mixing recursion and sorting is harder (I’ve yet to do that…).

In short: even if listing a folder was never guaranteed to be sorted alphabetically, most file systems do that by default (HFS+, NTFS, FAT32, most Linux variations). Having APFS not doing that results in a step backward in comparison (even if it may have some other useful tricks…).

Hello Arnaud,

Do you mind providing an example of the process you use? I’m struggling to make it work. Thanks.

Look the sample code there:


[quote=487295:@Michael Reade]Hello Arnaud,

Do you mind providing an example of the process you use? I’m struggling to make it work. Thanks.[/quote]
Hello Michael,

No problem, as long as I understood correctly what you want me to show (the loop to get items sorted alphabetically, correct?).

Here’s a way:

dim i As Integer
dim Source,f,Items() As FolderItem
dim Names() as String

if Source<>nil then
for i=0 to Source.Count-1 //Collect every item
if f<>nil then
Items.AddRow f
Names.AddRow f.DisplayName 'This is the trick: sorting folderitems isn’t doable alone (a folderitem isn’t just a name, it’s an object, thus you can’t specify the property you want for the sort. Instead, put it in another array).
end if
Names.SortWith Items 'Sort the Names array along with the Items array
end if

Hope this helps.

About 5 years ago the sort function in Xojo was updated to allow the use of a Delegate method to sort objects in an array (2015R3). So the way I do this is:

[code]Public Function SortFilesByName(Value1 As FolderItem, Value2 As FolderItem) as Integer
If Value1.Name > Value2.Name Then
Return 1
End If

If Value2.Name > Value1.Name Then
Return -1
End If

Return 0
End Function

This is my sort function and I use this with

[code]// Load a table of the contents of f
Dim Files() As FolderItem

For i As Integer = 0 To f.Count - 1
Files.AddRow(f.ChildAt(i), False)

Files.Sort(AddressOf SortFilesByName)

Where f is the folder I want sorted.

You’ll notice this is just like using custom sort on a listbox column.

I could also create delegate methods to sort by createddatetime or modifieddatetime or even size (which would require creating a binary input stream for each file and comparing the length of each stream) and then just use the delegate of choice to get the result I desired.

This is a great addition, thanks for sharing it!

I’ll never understand why so many language additions like this one are never promoted enough. Undoubtedly, they have appeared in some “release notes” hidden somewhere, but the fact is a lot of those additions are easily not seen until someone eventually mentions them, years later. It’s not the first one I discover (being told or by myself) at all, and that’s a real shame.