Android Code Snippet [B4X] CopyFolder / DeleteFolder

A recursive sub that copies a complete folder.

B4X:
Private Sub CopyFolder(Source As String, targetFolder As String)
   If File.Exists(targetFolder, "") = False Then File.MakeDir(targetFolder, "")
   For Each f As String In File.ListFiles(Source)
     If File.IsDirectory(Source, f) Then
       CopyFolder(File.Combine(Source, f), File.Combine(targetFolder, f))
       Continue
     End If
     File.Copy(Source, f, targetFolder, f)
   Next
End Sub

Note that it will not work with the assets folder. You can instead create a zip file and unpack it with the Archiver library.

Recursively delete a folder and its sub folders:
B4X:
Sub DeleteFolder (folder As String)
   For Each f As String In File.ListFiles(folder)
       If File.IsDirectory(folder, f) Then
           DeleteFolder(File.Combine(folder, f))
       End If
       File.Delete(folder, f)
   Next
End Sub


Tags: Copy, Folder, Directory
 
Last edited:

DonManfred

Expert
Licensed User
Longtime User

Robert Valentino

Well-Known Member
Licensed User
Longtime User
Recursively delete a folder and its sub folders:
B4X:
Sub DeleteFolder (folder As String)
   For Each f As String In File.ListFiles(folder)
       If File.IsDirectory(folder, f) Then
           DeleteFolder(File.Combine(folder, f))
       End If
       File.Delete(folder, f)
   Next
End Sub
Tags: Copy, Folder, Directory

B4X:
DeleteFolder Passed:/storage/emulated/0/BOBs/BBS/
DeleteFolder Passed:/storage/emulated/0/BOBs/BBS/Backups
DeleteFolder Delete:/storage/emulated/0/BOBs/BBS/Backups/BBS-01.db
DeleteFolder Delete:/storage/emulated/0/BOBs/BBS/Backups/BBS-02.db
DeleteFolder Delete:/storage/emulated/0/BOBs/BBS//Backups
DeleteFolder Delete:/storage/emulated/0/BOBs/BBS//BBS.db
DeleteFolder Delete:/storage/emulated/0/BOBs/BBS//BBS.db-journal
DeleteFolder Delete:/storage/emulated/0/BOBs/BBS//Messages.raf
DeleteFolder Delete:/storage/emulated/0/BOBs/BBS//NamesDB.db
DeleteFolder Passed:/storage/emulated/0/BOBs/BBS/PDFs
DeleteFolder Delete:/storage/emulated/0/BOBs/BBS//PDFs
DeleteFolder Passed:/storage/emulated/0/BOBs/BBS/SnapShots
DeleteFolder Delete:/storage/emulated/0/BOBs/BBS//SnapShots
DeleteFolder Passed:/storage/emulated/0/BOBs/BBS/Temporary
DeleteFolder Delete:/storage/emulated/0/BOBs/BBS/Temporary/BracketsPreSeating.lst
DeleteFolder Delete:/storage/emulated/0/BOBs/BBS//Temporary
DeleteFolder Delete:/storage/emulated/0/BOBs/BBS//UserPreferences.raf
DeleteFolder Delete:/storage/emulated/0/BOBs/BBS//.DeviceID.bbs
DeleteFolder Delete:/storage/emulated/0/BOBs/BBS//Replay.raf

I found that the above code was not deleting the passed folder [/storage/emulated/0/BOBs/BBS/] after deleting all the files and sub folders - to get it to delete the passed folder as well I had to change it to this. WAS the intent not to delete the passed folder?

NOTE: Deletes are commented out because just testing right now.

B4X:
Public  Sub DeleteFolder(folder As String)
            
            Log("cFile::DeleteFolder Passed:" &folder)
            
               For Each f As String In File.ListFiles(folder)
                   If  File.IsDirectory(folder, f) Then
                       DeleteFolder(File.Combine(folder, f))
                   Else                
                    Log("cFile::DeleteFolder   File:" &folder &"/" &f)
                
 '                  File.Delete(folder, f)
                End If
               Next
            
            Log("cFile::DeleteFolder    Dir:" &folder)
'              File.Delete(folder, "")            
End Sub


cFile::DeleteFolder Passed:/storage/emulated/0/BOBs/BBS/
cFile::DeleteFolder Passed:/storage/emulated/0/BOBs/BBS/Backups
cFile::DeleteFolder   File:/storage/emulated/0/BOBs/BBS/Backups/BBS-01.db
cFile::DeleteFolder   File:/storage/emulated/0/BOBs/BBS/Backups/BBS-02.db
cFile::DeleteFolder    Dir:/storage/emulated/0/BOBs/BBS/Backups
cFile::DeleteFolder   File:/storage/emulated/0/BOBs/BBS//BBS.db
cFile::DeleteFolder   File:/storage/emulated/0/BOBs/BBS//BBS.db-journal
cFile::DeleteFolder   File:/storage/emulated/0/BOBs/BBS//Messages.raf
cFile::DeleteFolder   File:/storage/emulated/0/BOBs/BBS//NamesDB.db
cFile::DeleteFolder Passed:/storage/emulated/0/BOBs/BBS/PDFs
cFile::DeleteFolder    Dir:/storage/emulated/0/BOBs/BBS/PDFs
cFile::DeleteFolder Passed:/storage/emulated/0/BOBs/BBS/SnapShots
cFile::DeleteFolder    Dir:/storage/emulated/0/BOBs/BBS/SnapShots
cFile::DeleteFolder Passed:/storage/emulated/0/BOBs/BBS/Temporary
cFile::DeleteFolder   File:/storage/emulated/0/BOBs/BBS/Temporary/BracketsPreSeating.lst
cFile::DeleteFolder    Dir:/storage/emulated/0/BOBs/BBS/Temporary
cFile::DeleteFolder   File:/storage/emulated/0/BOBs/BBS//UserPreferences.raf
cFile::DeleteFolder   File:/storage/emulated/0/BOBs/BBS//.DeviceID.bbs
cFile::DeleteFolder   File:/storage/emulated/0/BOBs/BBS//Replay.raf
cFile::DeleteFolder    Dir:/storage/emulated/0/BOBs/BBS/
 

ilan

Expert
Licensed User
Longtime User
Recursively delete a folder and its sub folders:
B4X:
Sub DeleteFolder (folder As String)
For Each f As String In File.ListFiles(folder)
If File.IsDirectory(folder, f) Then
DeleteFolder(File.Combine(folder, f))
End If
File.Delete(folder, f)
Next
End Sub
Tags: Copy, Folder, Directory

i have a question related to this code

if i have 3 files and 2 folders in my dir.internal folder

now in the loop the first file will be deleted, then the second and the third file. when the IsDirectory return true it change the folder string to the new folder like:
file.dirinternal & "/" music

so now the loop will exit and the sub will be called again but the last folder will not be deleted right?
 

OliverA

Expert
Licensed User
Longtime User
so now the loop will exit and the sub will be called again but the last folder will not be deleted right?
No. The loop will not exit without first calling File.Delete on the directory
 

ilan

Expert
Licensed User
Longtime User
No. The loop will not exit without first calling File.Delete on the directory

i am not sure this is true, because i make a simple test and i get a different result

B4X:
    '...
    recursiveTest(3)
End Sub

Sub recursiveTest(nr As Int)
    For i = 0 To nr
        If i = 2 Then
            recursiveTest(3)
        End If
        Log(i)
    Next
End Sub

according to what you say i should get in the logs of 0,1,2,3 and then again 0,1,2,3, ....
but because i am calling inside the loop the method again it will exit the loop and i get in the logs 0,1,0,1,0,1.... (infinite loop until b4j crash)
so how will the code above finish remove all folders? it doesn't make any sense to me.

if i have in my folder 3 folders and 3 files as soon as the loop meats the folder it will only delete what is iniside this folder and not the folder itself.
 

ilan

Expert
Licensed User
Longtime User
If you have any other question then it is better to start a new thread.

i just wanted to understand the code and learn from it (to another scenario). I believe that it is working but i dont understand how.

if it clears everything inside a folder then it will also delete subfolder with subfolders with files inside? But how if you always exit the loop and change the folder name?
 

ilan

Expert
Licensed User
Longtime User
What exactly are you trying to archieve?

i want to understand the code because from what i have learned until now it should not work as expected but the fact is that it works and i dont understand why. so i am missing something that may be very important related to loops.

anyway, i will open a new thread maybe in the "Teaching Programming" section.
 

DonManfred

Expert
Licensed User
Longtime User
B4X:
Sub DeleteFolder (folder As String)
    Log($"Deletefolder(${folder})"$)
    For Each f As String In File.ListFiles(folder)
        If File.IsDirectory(folder, f) Then
            Log($"Deletefolder.Recursivecall to DeleteFolder(${folder},${f} -> ${File.Combine(folder, f)})"$)
            DeleteFolder(File.Combine(folder, f))
        End If
        Log($"Deletefolder.File.Delete(${folder},${f})"$)
        File.Delete(folder, f)
    Next
End Sub

Deletefolder(D:\Work\temp)
Deletefolder.Recursivecall to DeleteFolder(D:\Work\temp,ilan -> D:\Work\temp\ilan)
Deletefolder(D:\Work\temp\ilan)
Deletefolder.File.Delete(D:\Work\temp\ilan,INT_Bildwelt_KF410_HomePure_iso.jpg)
Deletefolder.File.Delete(D:\Work\temp\ilan,m19texmbz3rtzdslw47patrh67b2cs9t.pdf)
Deletefolder.File.Delete(D:\Work\temp\ilan,ME_KF410_ALU_HP.png)
Deletefolder.Recursivecall to DeleteFolder(D:\Work\temp\ilan,subfolder -> D:\Work\temp\ilan\subfolder)
Deletefolder(D:\Work\temp\ilan\subfolder)
Deletefolder.File.Delete(D:\Work\temp\ilan\subfolder,6226_Zusatzmaterial.zip)
Deletefolder.File.Delete(D:\Work\temp\ilan,subfolder)
Deletefolder.File.Delete(D:\Work\temp,ilan)
Deletefolder.File.Delete(D:\Work\temp,INT_Bildwelt_KF410_HomePure_iso.jpg)
Deletefolder.File.Delete(D:\Work\temp,lh9f559b9viusmdjn5zzixsof30c8k0i.pdf)
Deletefolder.File.Delete(D:\Work\temp,m19texmbz3rtzdslw47patrh67b2cs9t.pdf)
Deletefolder.File.Delete(D:\Work\temp,ME_KF410_ALU_HP.png)

D:\Work\temp is the starting folder. here i did created a folder ilan and put some files into. i created a subfolder inside ilan folder and put files here too.
I then run DeleteFolder("D:\Work\temp") and expect to "empty the temp folder inclusing all subfolders"

I used B4J to test but it will work in android the same.
 
Last edited:

Midimaster

Active Member
Licensed User
As I read from your question you cannot understand how the recursion runs?

Well, if you start the first call it will scan the folder. And when the function hits a sub-folder it does not delete the sub-folder but calls the function "DeleteFolder", which means that this level of recursion is stopped immediately and a new deeper level of the same function is opened.

If this 2nd level function again hits a subfolder it jumps down to the next depth of recursion level. This goes as long as the functions find subfolder. Only when a folder (lets say level 3) has no more subfolders the function start to delete the contained files. Then jumps a level higher, back to the loop where it currently scans the level 2. At first it deletes the now empty folder then scan the other filenames of level 2. When it finds another subfolder it jumps again down to level 3 and returns back to the scanning. All files in this level will be deleted too.

So each jumpback ends with the deleting of the now empty folder. If a filename is no folder it deletes it also. When one folder of level 2 is cleared this way it jumps back to level 1 and deletes this empty level 2 folder. After that it can again find another level 2 folder and the recursion starts again getting deeper an deeper.

If all subfolders in level 1 are empty and deleted (and also the files in the root folder) it jumps back to the very first called function and now deletes the (meanwhile empty) root folder.
 

ilan

Expert
Licensed User
Longtime User
i opened a thread please put your questions/answers there. like this we wont have a salad here :)
 
Last edited:

Tempomaster

Active Member
Licensed User
Longtime User
Hello,

I have used the "copyfolder" routine to copy large amounts of files and directories without any problems. On Android 11, after some time without errors, copying was simply interrupted while working. An indefinite number of files and directories were not copied. I moved this routine to a service and called it in main.activity:

CallSubDelayed3 (copy, "copyfolder", source, destination)

So it works fine now. I just don't understand why that is.
 
Top