Announcement

Collapse
No announcement yet.

Listing SubFolders in 10 lines of code

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Listing SubFolders in 10 lines of code

    I was reading several of the threads on listing subdirectories and the code struck me as perhaps more complicated than I wanted it to be.

    So I wrote a non-recursive, 10-line subroutine that will create the listing (ok, there's also a couple of DIM lines, too, including a Global array where the results are stored).

    Code:
    Sub ListSubFolders(startfolder$)            'Start$ cannot end in \
        'returns list of folder (full paths) in Folder() - unsorted
        Dim iPOS As Long
        Folder(FolderCount) = startfolder$
        While Len(Folder(iPOS))
            temp$ = Dir$(Build$(Folder(iPOS),"\*.*"), Only %SubDir)  'subfolders only
            While Len(temp$)
                Incr FolderCount
                Folder(FolderCount) =  Build$(Folder(iPos),"\",temp$)
                temp$ =  Dir$ (Next)
            Wend
            Incr iPOS
        Wend
    End Sub
    This example lists subfolders only. Use the following line to change it to include normal files.

    Code:
    temp$ = Dir$(Build$(Folder(iPOS),"\*.*"), %SubDir)       'subfolders + files
    In my search I didn't see anyone using this particular algorithm to create a subdirectory listing.

    As a minimalist kind of programmer, I like the compactness - not to mention how easy it is to understand.

    On small directory structures it's very fast - basically instant response. On a full c-drive it took about 1 minute to read about 10,000 subfolders. I don't know enough about DIR$ to know whether the number of files matters in how fast it works, or if just the number of subfolders is the determining factor.

    I keep meaning to copy one of the recursive versions and do a speed comparison.

    Once the code is used, Window keeps all of the directory info in a cache, so doing tests means I have to reboot or, if I knew how, clear the cache to get valid answers. Does anyone know an easy way to clear the cache so subsequent runs of the code won't give wrong answers (basically instant response for an entire drive).

    I don't do subfolder listings all that often so I've not given much thought on how to speed this up. I assume there is an API that DIR$ draws on. Would that speed this up significantly?

    Below is a complete PowerBASIC app that puts the results into a listbox.

    Note that I dimensioned the array to hold 10,000 subfolders. To list files, a much larger array is needed. Also, the subroutine returns the list unsorted. In this example, the listbox sorts it, but I could have used ARRAY SORT.

    Another trick I used is to create the listbox after the list array was created. That way I can load an entire array of data in one statement. That brings up a question - can I load an array to a listbox, adding the array content to what is already in the listbox? Help doesn't say I can.


    Code:
       #Compile Exe
       Global hDlg As Dword
       Global Folder() As String, FolderCount As Long
       Function PBMain() As Long
          Dialog New Pixels, 0, "ListBox Test",300,100,230,300, _
                                          %WS_OverlappedWindow, 0 To hDlg
          Control Add Button, hDlg, 100,"Start Search", 10,10,100,20
          Control Add Label, hDlg, 150,"", 120,10,100,20, %WS_Border Or %SS_Center
          Dialog Show Modal hDlg Call DlgProc
       End Function
    
       CallBack Function DlgProc() As Long
          If Cb.Msg = %WM_Command And Cb.Ctl = 100 And Cb.CtlMsg = %BN_Clicked Then
             Dim Folder(10000)
             ListSubFolders("d:\temp")
             ReDim Preserve Folder(FolderCount)
             Control Add ListBox, hDlg, 200, Folder(), 10,40,210,250
             Control Set Text hDlg, 150, Str$(FolderCount+1)
          End If
       End Function
    
    Sub ListSubFolders(startfolder$)            'Start$ cannot end in \
        'returns list of folder (full paths) in Folder() - unsorted
        Dim iPOS As Long
        Folder(FolderCount) = startfolder$
        While Len(Folder(iPOS))
            temp$ = Dir$(Build$(Folder(iPOS),"\*.*"), Only %SubDir)  'subfolders only
            While Len(temp$)
                Incr FolderCount
                Folder(FolderCount) =  Build$(Folder(iPos),"\",temp$)
                temp$ =  Dir$ (Next)
            Wend
            Incr iPOS
        Wend
    End Sub
    I can think of a few data verification things that would make it safer, like verifying that the starting folder is valid. Or, a separate array for file and for folders would also be convenient in some situations.
    Last edited by Gary Beene; 17 Feb 2009, 11:07 AM.

  • #2
    Gary,

    One of those things you *might* want to consider is the potential GPF if the number of folders/items exceeds your initial array bounds (>10,000 in this case). Here's a trick many have used in the past to avoid this kind of thing.
    Code:
          While Len(temp$)
                Incr FolderCount
                [COLOR="DarkRed"][b]IF FolderCount > UBOUND(Folder()) THEN
                  REDIM PRESERVE Folder(FolderCount + 100)
                END IF[/b][/COLOR]
                Folder(FolderCount) =  Build$(Folder(iPos),"\",temp$)
                temp$ =  Dir$ (Next)
          Wend
    You have to consider the time required to REDIM the array, but its still better than getting a GPF in the middle of the program for no apparent reason
    Software makes Hardware Happen

    Comment


    • #3
      Hi Joe,

      Yes, that's a good reminder. I actually got the PDF a few times when I was testing the code and realized that my array dimension was the cause.

      I hate the part where making an algorithm safe takes more lines of code than the algorithm itself!

      Comment


      • #4
        What would be really helpful would be an API that can gives me the number of subfolders a folder has - just like a TreeView control can tell me how many items it has. Even if I could only get the number of subfolders on a drive, that would be better than guessing.

        Anyone heard of such an API?

        Comment


        • #5
          I hate the part where making an algorithm safe takes more lines of code than the algorithm itself!
          hummm... ok, then make it a marco
          Software makes Hardware Happen

          Comment


          • #6
            From experiance:

            Ordinary enums like these are terribly slow.
            And i don't mean the redim's but the actual reading.
            And there is only one solution, through com.

            Yes, pidl's and other terrible stuff.
            hellobasic

            Comment


            • #7
              What would be really helpful would be an API that can gives me the number of subfolders a folder has - just like a TreeView control can tell me how many items it has.

              Anyone heard of such an API?
              I haven't, but even if I had, it would not be a 100% thing like a treeview control. Why not? Because another user could add or delete a folder between the time you GET the count and the time you actually USE that count.

              With a treeview control, that can't happen... you can count the number of items in the control any time and know it won't change until YOU make it change.

              MCM
              Michael Mattias
              Tal Systems (retired)
              Port Washington WI USA
              [email protected]
              http://www.talsystems.com

              Comment


              • #8
                >With a treeview control, that can't happen... you can count the number of items in the control any time and know it won't change until YOU make it change.

                Not sure what you mean but during population of a node (folder) you get a list (if done via com) and if you do it right you watch for a specific event related to folder or file removal.
                This is how Windows Explorer works.
                On specific event it add's or deletes an item.
                hellobasic

                Comment


                • #9
                  >On specific event it add's or deletes an item.

                  That's just like Win32(SDK): Internet Cookie Monitor April 25, 2001 works.

                  On the Change event notification, you do a TreeView_InsertItem. YOU do it.

                  But I suppose you could ....
                  Code:
                  Lock out all other processes (yes, doable) 
                  Get the count of subfolders
                  Set up change notification event
                  Free up other processes
                  And on qualifying event, increment or decrement your count.

                  Then you only have uncertainty about what users on OTHER computers do to shared drives whilst processes in THIS computer are locked.

                  Better I think to 'size as you go.' If the data are changing that much/that often, the best you can do is a 'snapshot' anyway.

                  MCM
                  Michael Mattias
                  Tal Systems (retired)
                  Port Washington WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment


                  • #10
                    Define snapshot, imo not possible or workable since things may change constantly.

                    In Explorer the folders are added to a node on expand.
                    Enumeration is fast due the fact of caching, if not cached you'll notice.
                    Sometimes it is slower isn't?
                    However that cache is not related to controls like in the Explorer, it's the filesystem.
                    The folderview (Explorer) will avoid holding items in memory since it has no use except what is currently required to have like the 'friendly name' for a folder.
                    Folders are pidls and you should not take it out of perspective, i mean enumming via a dir$ is just a secundairy method.
                    Windows folders are more com based as you may think.
                    Therefore these relative folders like the desktop and my documents etc.
                    These are namespaces.

                    I find pidls rather difficult, relative, not relative but the fastest way to obtain foldernames and attributes is through com.
                    hellobasic

                    Comment

                    Working...
                    X