Android Question Get number of subfolder levels in a folder

Ivan Aldaz

Member
Licensed User
Longtime User
Hi all.

For my app I need to know the number of subfolder levels that a given folder has. Not the number of folders and subfolders, but the 'depth' of the folders structure. I've tried with something like
B4X:
Sub CountDirLevels(Folder As String) As Int
   
  Dim level As Int = 0
   
  For Each f As String In File.ListFiles(Folder)
       
     If File.IsDirectory(Folder, f) Then
         level = level + 1
         CountDirLevels(File.Combine(Folder, f))
     End If
       
   Next
   
  Return level
   
End Sub

...but doesn't work, because 'level' increases with every folder that the code finds.

I've been trying for a long time, but haven't found the way, and looked for it in the forum, but no luck.

Any ideas?
 

DonManfred

Expert
Licensed User
Longtime User
Check this class. Even if the Class is nto exactly what you are searching it may be a help finding a Solution.

https://www.b4x.com/android/forum/t...-get-list-of-files-using-wildcards-iii.44922/

A Sample project is attached... It counts the list of folders and all subfolders of a given path.

B4X:
Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Dim wcl As wildcardlisting
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
    wcl.Initialize(Me,"wcl")

    wcl.ClearLists
    ' It cleares the Dir- and Filelisting lists which will be used in Events
    '
    wcl.ListFolders(File.DirRootExternal, True, True, True) ' Set the 1st boolean to false if you don´t want to recurse the tree...
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub


Sub wcl_FilesAndFoldersFinish(DirListing As List, FileListing As List)
    Log("wcl_FilesAndFoldersFinish("&DirListing.Size&","&FileListing.Size&")")
    For i = 0 To DirListing.Size -1
        'Log(DirListing.Get(i))
    Next
    For i = 0 To FileListing.Size -1
        Log(FileListing.Get(i))
    Next
End Sub
Sub wcl_DirListingError(error As String)
    Log("wcl_DirListingError("&error&")")
End Sub
Sub wcl_ListFilesFinish(FileListing As List)
    Log("wcl_ListFilesFinish("&FileListing.Size&")")
    For i = 0 To FileListing.Size -1
        Log(FileListing.Get(i))
    Next
End Sub
Sub wcl_ListFoldersFinish(DirListing As List)
    Log("wcl_ListFoldersFinish("&DirListing.Size&")")
    For i = 0 To DirListing.Size -1
        'Log(DirListing.Get(i))
    Next
End Sub

*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
wcl.Initialize(wcl)
ListFolders(/storage/emulated/0)
Dirlisting.Size = 2685
** Activity (main) Resume **
wcl_ListFoldersFinish(2685)
** Activity (main) Pause, UserClosed = false **
** Activity (main) Resume **

At least you can use the List of all found folders and iterate through them. You can count the slashes to find the amount of subfolder-levels...

Maybe something like this

B4X:
Sub wcl_ListFoldersFinish(DirListing As List)
    Log("wcl_ListFoldersFinish("&DirListing.Size&")")
    Dim maxlevel As Int = 0
    For i = 0 To DirListing.Size -1
        Dim count As Int
        Dim dir As String = DirListing.Get(i)
        Dim m As Matcher = Regex.Matcher("/", dir)
        Do While m.Find
            count = count +1
        Loop
         maxlevel = Max(count,maxlevel)
    Next
    Log("MaxLevel: "&maxlevel)
End Sub
 

Attachments

  • wildcardtest.zip
    8.7 KB · Views: 155
Last edited:
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
This code substracts the starting paths slashes....
B4X:
Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Dim wcl As wildcardlisting
    Dim path As String
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
    wcl.Initialize(Me,"wcl")
   
    wcl.ClearLists
    ' It cleares the Dir- and Filelisting lists which will be used in Events
    '
    path = File.DirRootExternal
    wcl.ListFolders(File.DirRootExternal, True, True, True)
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub


Sub wcl_FilesAndFoldersFinish(DirListing As List, FileListing As List)
    Log("wcl_FilesAndFoldersFinish("&DirListing.Size&","&FileListing.Size&")")
    For i = 0 To DirListing.Size -1
        'Log(DirListing.Get(i))
    Next
    For i = 0 To FileListing.Size -1
        Log(FileListing.Get(i))
    Next
End Sub
Sub wcl_DirListingError(error As String)
    Log("wcl_DirListingError("&error&")")
End Sub
Sub wcl_ListFilesFinish(FileListing As List)
    Log("wcl_ListFilesFinish("&FileListing.Size&")")
    For i = 0 To FileListing.Size -1
        Log(FileListing.Get(i))
    Next
End Sub
Sub wcl_ListFoldersFinish(DirListing As List)
    Log("wcl_ListFoldersFinish("&DirListing.Size&")")
    Dim maxlevel As Int = 0
    For i = 0 To DirListing.Size -1
        Dim count As Int
        Dim dir As String = DirListing.Get(i)
        dir = dir.SubString(path.Length)
        Dim m As Matcher = Regex.Matcher("/", dir)
        Do While m.Find
            count = count +1
        Loop
         maxlevel = Max(count,maxlevel)
    Next
    Log("MaxLevel: "&maxlevel)
End Sub
 
Upvote 0

Ivan Aldaz

Member
Licensed User
Longtime User
Thanks for your prompt answer, Manfred. I think this code only calculates the max level from a list of paths, but doesn't do it recursively, to find subfolders inside folders.
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
I think this code only calculates the max level from a list of paths
which is evaluated before (RECURSIVE in my example) by the Class.

but doesn't do it recursively, to find subfolders inside folders
Add a log of all found folders and you´ll see that IT IS a recursive list...
B4X:
 For i = 0 To DirListing.Size -1
        Log(DirListing.Get(i))
Next

The 1st boolean in
B4X:
 wcl.ListFolders(File.DirRootExternal, True, True, True)
is recursive. If set to false then it will only list in the folder you specifiy. If set to true then the list will contains ALL folders recursively starting from the folder you specified.
 
Last edited:
Upvote 0

Ivan Aldaz

Member
Licensed User
Longtime User
Well, after taking the idea of counting levels (slashes) from the string of the full path, I have simplified the task.

First, in Sub "GetDirs" we populate a list with the full path of all the folders and subfolders (sub much simpler than the one in the class of post #2), and then, in Sub "CaculateLevel" (is exactly Sub "wcl_ListFoldersFinishprovided" by DonManfred in post #3), count slashes of each item in the list. Just need to use a Global list (listFolders).

B4X:
Sub Globals

    Dim listFolders as list
    Dim pathToCount as string

End Sub

Sub Activity_Create

    pathToCount = File.DirRootExternal   'Here the path of your choice
    Dim levels as int = CountDirLevels(pathToCount)

    Log("Levels: " & levels)

End Sub


Public Sub CountDirLevels(path1) As Int

   GetDirs(path1)

   Return CalculateLevel(listFolders)

End Sub

Sub GetDirs(Folder As String)

'Populates a list with the full path of all folders and subfolders

   For Each f As String In File.ListFiles(Folder)
  
      If File.IsDirectory(Folder, f) Then
  
           listFolders.Add(File.Combine(Folder, f))
           GetDirs(File.Combine(Folder, f))

       End If

   Next

End Sub


Sub CalculateLevel(dirsList As List) As Int
  Dim maxLevel As Int = 0

  For i = 0 To dirsList.Size -1
    
     Dim dir As String = dirsList.Get(i)
           dir = dir.SubString(path.Length)
     Dim m As Matcher = Regex.Matcher("/", dir)
     Dim count As Int

     Do While m.Find
         count = count + 1
     Loop

      maxLevel = Max(count, maxLevel)
  Next

  Log("MaxLevel: " & maxLevel)

   Return maxLevel

End Sub
 
Upvote 0

Misterbates

Active Member
Licensed User
Your original post didn't ask for the depth from root, rather it asked ...
I need to know the number of subfolder levels that a given folder has. Not the number of folders and subfolders, but the 'depth' of the folders structure.

If that's really what you want, then try this:
B4X:
Sub Activity_Create(FirstTime As Boolean)
    Dim pathToCount As String = File.DirRootExternal   'Here the path of your choice
    Dim levels As Int = CountDirLevels(pathToCount)
    Log($"$2.0{levels} FOR: ${pathToCount}"$)
End Sub

private Sub CountDirLevels(Path As String) As Int
    Dim levels As Int = 0
    For Each f In File.ListFiles(Path)
        If File.IsDirectory(Path, f) Then
            levels = Max(levels, 1 + CountDirLevels(File.Combine(Path, f)))
            Log($"$2.0{levels} ${File.Combine(Path, f)}"$)
        End If
    Next
    Return levels
End Sub
 
Upvote 0

Ivan Aldaz

Member
Licensed User
Longtime User
Wow!!! This is THE SOLUTION. I knew it had to be a simpler and more elegant way! Thank you very much, Misterbates.

BTW, in the code of post #7, depth wasn't measured from root; the beginning was defined by
B4X:
dir = dir.SubString(path.Length)
 
Upvote 0
Top