Need "For Each" to read files in numerical order.

Mugsy's RapSheet 156 Reputation points
2022-10-22T21:01:47.883+00:00

My program reads a collection of numbered png images (eg: icon00.png…icon199.png) using a "For…Each" loop and displays them in a ListView box.

Problem: After "Icon10.png", it reads "Icon100.png", "Icon101.png"… assumedly in alphabetical order. :( I need it to read "11" after "10", and "100" after "99".

            intCnt = 1  
            For Each ClosetFile As String In IO.Directory.GetFiles(strClosetPath, strCategory & "*.png", SortOrder.Ascending)  '  "ClosetFile" reads "icon100" after "icon10".  
                Dim img = Image.FromFile(ClosetFile)  
                ImageList2.Images.Add((intCnt - 1).ToString, img)  
                img.Dispose()  
                strRawName = strIconname   
                lsvCollection.Items.Add(ParseItemName(strRawName), (intCnt - 1).ToString)  
                intCnt += 1  
            Next  
            intTotalNumberOfFiles = intCnt - 1  
  

Is there a way to force "For… Each" to read files in numerical order instead of (apparently) alphabetical, or do I have to just read them all and sort them ex post facto? (Note: renumbering user's files is not an option.) :(

TIA

VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,637 questions
0 comments No comments
{count} votes

3 answers

Sort by: Most helpful
  1. LesHay 7,126 Reputation points
    2022-10-22T21:49:27.43+00:00

    Hi
    I am not aware of any inbuit method other than using a SortedDictionary. Here is an example. I used a Function which helps if you need to reuse at other places. To prove the sort, you can manually reorder the testnames to mix them up differently.

    Public Class Form1  
      ' this to simulate file naames from  
      ' HDD. Manually mixed up to prove  
      ' the sort.  
      Dim testnames() As String = {"icon101", "icon2", "icon99", "icon10", "icon1", "icon11", "icon100", "icon1000"}  
      Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load  
        With ListBox1  
          .DataSource = New BindingSource(GetFls, Nothing)  
          .DisplayMember = "value"  
        End With  
      End Sub  
      Function GetFls() As SortedDictionary(Of Integer, String)  
        Dim dic As New SortedDictionary(Of Integer, String)  
      
        ' You would read the names as  
        ' usual into a string array  
        ' sorting unecessary.  
      
        ' Dim testnames() As String = IO.Directory.GetFiles(strClosetPath, "*.png")  
      
        For Each s As String In testnames  
          dic.Add(CInt(s.Replace("icon", Nothing)), s)  
        Next  
        Return dic  
      End Function  
    End Class  
    

  2. Mugsy's RapSheet 156 Reputation points
    2022-10-23T02:01:45.477+00:00

    Thanks for the reply. I'll take a closer look at this in the morning.

    I thought I may have come up with a solution on my own but it didn't work. Since I can only add items to an ImageList sequentially, I tried creating an array of images, extracting the position from the filename, inserting them into the array at the proper position, and once complete, copying the sorted array to my "ImageList2".

    Everything but this last step works:

            Dim imgImageArray(200) As Image ' Can only add images to ImageList sequentially, so we need an array to add them as read/randomly, added to list in order.  
            ...  
            For intCnt = 1 To intTotalNumberOfFiles             ' Load image array with sorted list.  
                ImageList2.Images.Add(imgImageArray(intCnt))  
            Next  
    

    When I try to copy "imgImageArray(x)" to ImageList, I get an "Invalid Parameter" error. No idea why.

    I'll try your method in the morning. Thx.

    0 comments No comments

  3. LesHay 7,126 Reputation points
    2022-10-23T18:22:38.323+00:00

    Hi
    OK, for the ImageList I added some code and editted accordingly. Once the SortedDictionary has been filled, a call to GetImages returns the images in the correct order (untested as I don't happen to have a folder of IconXXX.png handy), but the principle should work.

    Public Class Form1  
      ' this to simulate file naames from  
      ' HDD. Manually mixed up to prove  
      ' the sort.  
      Dim testnames() As String = {"icon101", "icon2", "icon99", "icon10", "icon1", "icon11", "icon100", "icon1000"}  
      Dim Dic As New SortedDictionary(Of Integer, String)  
      Dim imagelist2 As New ImageList  
      Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load  
        Dic = GetFls()  
        With ListBox1  
          .DataSource = New BindingSource(Dic, Nothing)  
          .DisplayMember = "value"  
        End With  
        imagelist2 = GetImages()  
      End Sub  
      Function GetFls() As SortedDictionary(Of Integer, String)  
        Dim dic As New SortedDictionary(Of Integer, String)  
      
        ' You would read the names as  
        ' usual into a string array  
        ' sorting unecessary.  
      
        ' Dim testnames() As String = IO.Directory.GetFiles(strClosetPath, "*.png")  
      
        For Each s As String In testnames  
          dic.Add(CInt(s.Replace("icon", Nothing)), s)  
        Next  
        Return dic  
      End Function  
      Function GetImages() As ImageList  
        Dim img As New ImageList  
        For Each kvp As KeyValuePair(Of Integer, String) In Dic  
          img.Images.Add(kvp.Key, Image.FromFile(kvp.Value & ".png"))  
        Next  
        Return img  
      End Function  
    End Class