0

this is my code

Dim orderedFiles = New System.IO.DirectoryInfo(dir).GetFiles("file_*.jpeg").OrderBy(Function(x) x.Name)

For Each f As System.IO.FileInfo In orderedFiles
msgbox(f.name)
Next

display

file_1.jpeg
file_10.jpeg
file_11.jpeg
file_12.jpeg
file_13.jpeg
file_14.jpeg
file_2.jpeg
file_3.jpeg
file_4.jpeg
file_5.jpeg
file_6.jpeg
file_7.jpeg
file_8.jpeg
file_9.jpeg

i want them to sort 1 - 2 - 3 ...... 14
how can i do it?

DREAM
  • 352
  • 1
  • 11
  • What order do you get if you don;t explicitly sort them? – jmcilhinney Apr 22 '20 at 17:04
  • 1
    They are already sorting correctly. They're being sorted by their ASCII values, so `1` followed by `10` is the correct order. The usual way to fix this issue is to add zeros on the left of the numbers that are a single digit, as in `01`, which will allow them to sort in the order you want. If that doesn't work for you, you're going to have to write your own code to do the sorting. – Ken White Apr 22 '20 at 17:05
  • @KenWhite, there actually is an API function that will compare/sort strings alphanumerically, which is how File Explorer is able to do it. I'm not sure whether `GetFiles` returns them in that order already, hence my question. I can't recall the specific API but it can be invoked in VB code if required. – jmcilhinney Apr 22 '20 at 17:07
  • 1
    I believe the API of interest is `StrCmpLogicalW`. – jmcilhinney Apr 22 '20 at 17:08
  • *"They are already being sorted alphanumerically"*. No they're not. They're being sorted alphabetically, i.e. the digits are treated as characters rather than numbers. If they were being sorted alphanumerically then the number 2 would be before the number 10. – jmcilhinney Apr 22 '20 at 17:11
  • @jmcilhinney: Hmmm.... I may have to stand corrected on my last comment. According to the docs for that function, it does in fact appear that it might work. Removing the comment for that reason. Thanks for the info. :-) There's a Delphi example of it's use [here on SO](https://stackoverflow.com/a/5134942/62576) that demonstrates it, also. – Ken White Apr 22 '20 at 17:11
  • 1
    I couldn't find a VB.Net example here at SO, but Google found one at https://bytes.com/topic/visual-basic-net/answers/835533-listview-filename-sort-sequence – Ken White Apr 22 '20 at 17:18
  • I just tried sorting an array of `FileInfo` objects using it and it didn't work. I did some explicit tests and, for me, it seemed to work when the two strings were different but, when they were the same, it seemed to think that the first was less than the second instead of their being equal. Not sure what's going on but it's too late here now for me to do any more testing. – jmcilhinney Apr 22 '20 at 17:30
  • It's not completely trivial, but a comparison routine that will get the ordering you want can be written. Step through the strings in parallel as long as both characters are equal and not numeric digits, and as soon as you hit a digit, assemble digit strings for the both of them, parse, and compare the numbers. The customer comparer can then be used as the input to the library sort routines. In total, my routine for this purpose is about 90 lines including whitespace. – Craig Apr 22 '20 at 17:41
  • 1
    problem solved! i set every file name padleft `000000` e.g `000001` and `000010` now everything is fine. thank you everyone – DREAM Apr 22 '20 at 17:52

2 Answers2

4

You can do what you want without changing the file names using the StrCmpLogicalW API, e.g.

Imports System.IO
Imports System.Runtime.InteropServices

Module Module1

    <DllImport("shlwapi.dll", CharSet:=CharSet.Unicode)>
    Private Function StrCmpLogicalW(x As String, y As String) As Integer
    End Function

    Sub Main()
        Dim files = New DirectoryInfo("D:\johnm\Documents\Test").GetFiles()

        Array.Sort(files,
                   Function(file1, file2) StrCmpLogicalW(file1.Name, file2.Name))

        For Each file In files
            Console.WriteLine(file.Name)
        Next

        Console.ReadLine()
    End Sub

End Module
jmcilhinney
  • 40,280
  • 5
  • 23
  • 39
0

problem solved! i just set every file name with padleft 000000
e.g 000001 and 000010 now everything is fine

code

Dim test1 As String = "1"
test1 = test1.ToString.PadLeft(6, "0"c)

display

000001
DREAM
  • 352
  • 1
  • 11
  • Can you explain how this worked with `New System.IO.DirectoryInfo(dir).GetFiles("file_*.jpeg")`? – Enigmativity Apr 23 '20 at 04:21
  • @Enigmativity, I was wondering the same thing. I can only assume that the OP is referring to how the files were created in the first place. – jmcilhinney Apr 23 '20 at 04:33