Recursive SD directory removal

Hi all,

I am using an Arduino Mega with an Ethernet shield.

I am creating an SD file explorer library that will work with my c# code and allow my to manipulate the SD contents from my c# applications. So far I can pull the entire file/folder listing from the SD, I can upload files from the SD, I can create new directories and I can delete files. The problem I'm having is doing a recursive SD.rmdir() call. The documentation for the rmdir() method states that the directory must be empty, so I have created a recursive method in the Arduino to remove the deepest files/folder first add work back up the folder branch removing folders as it goes. Unfortunately every call to rmdir I make fails.

Here is the directory structure I am trying to remove.... XX |---YY | |---ZZ | | |---XYZ |---ASDF

and here is the serial output from the Arduino.... Removing: XX/ removing folder XYZ - fail removing folder ZZ - fail removing folder YY - fail removing folder ASDF - fail removing folder / - fail Removing the root - Fail

And here is the Arduino code to remove the directories...

void deleteFolder()
{

    Serial.print("Removing: "); Serial.println(inBuffer+1);
    File dir = SD.open(inBuffer + 1, FILE_WRITE);
    if (dir)
    {
        deleteRecurse(dir);
        dir.close();        
    }
    else
    {
        Serial.print("Could not open "); Serial.println(inBuffer + 1);
    }

    Serial.print("Removing the root");
    if (SD.rmdir(inBuffer + 1))
    {
        Serial.println(" - Sucuess");
    }
    else
    {
        Serial.println(" - Fail");
    }

}
void deleteRecurse(File dir)
{
    dir.rewindDirectory();
    while (true)
    {
        File nextDir = dir.openNextFile();
        if (!nextDir)
        {
            //no more, delete the directory
            Serial.print("Removing folder "); Serial.print(dir.name());
            if (SD.rmdir(dir.name()))
            {
                Serial.println(" - Sucess");
            }
            else
            {
                Serial.println(" - Fail");
            }
            break;
        }
        else
        {
            if (nextDir.isDirectory())
            {
                deleteRecurse(nextDir);
            }
            else
            {
                //delete the file               
                Serial.print("Removing file "); Serial.print(nextDir.name());
                if (SD.remove(nextDir.name()))
                {
                    Serial.println(" - Sucess");
                }
                else
                {
                    Serial.println(" - Fail");
                }
            }
        }
    }
}

Can anyone see what might be the issue? Thanks for looking Kevin

as part of the SD library, there is a function SdFile::rmRfStar() which does exactly what you are trying to do.

blh64: as part of the SD library, there is a function SdFile::rmRfStar() which does exactly what you are trying to do.

Ok. I see it in the library, but how do I get to it so I can use it?

How to you call a library function? Really? That is left as an exercise for the reader. Do SOME amount of work.

blh64:
Do SOME amount of work.

Firstly I do appreciate help whenever I get it, but making a post that has no constructive adds to the topic is just stupid. It wastes my time, it wastes your time and it wastes the time of everyone who maybe looking for the same information. So do us all a favor and if your post doesn’t help, keep it to yourself.

Secondly, if you think I haven’t done any work, then you didn’t bother the read my first post where posted my code that did not happen to just fall from the sky. Now I could image your comment would be justified had I not posted a potential solution, or if I had simply asked how do I <insert something here>, but that’s not the case. Maybe you just didn’t read it. Either way please refer to my previous comment.

blh64:
How to you call a library function?

Yes that was my second question. How do you call the rmRfStar method from within a private member of class? Since the method is not exposed outside the class, the question was meant for you to elaborate on your suggestion. What I have found is that you need to use the SdFat library written by user member fat16lib. Although the SD library published by Arduino does contain an SdFat utility it is not the same library that seems to be needed. I’ll just leave it as an excercize for you to read from here https://forum.arduino.cc/index.php?topic=115016.0

blh64:
Really?

Really. Please think twice about posting if it does help the thread.

If anyone else has constructive input about how to do this I would appreciate the help as I am closer to a solution, I don’t yet have something that works.

Looks like 'SD.rmdir()' in the built-in SD library removes the directory and all the files and directories it contains.

boolean SDClass::rmdir(const char *filepath) {
  /*
  
    Remove a single directory or a heirarchy of directories.

    A rough equivalent to `rm -rf`.
  
   */
  return walkPath(filepath, root, callback_rmdir);
}

johnwasser:
Looks like ‘SD.rmdir()’ in the built-in SD library removes the directory and all the files and directories it contains.

I’m not so sure about that. The following code creates a directory with 2 nested directories and tries to remove only the root which fails. It then successfully removes the nest directories piece wise.

#include <SD.h>
void setup()
{
const char* success = " - success";
const char* fail=" - fail";

  // Open serial communications and wait for port to open:
  Serial.begin(9600);

  while (!initializeSD())
  { Serial.println("SD card failed");
    delay(1);
  }

  //create some directories and try to remove only the root
Serial.print("Making AA/BB/CC");
if(SD.mkdir("AA/BB/CC"))
{   Serial.println(success);}
else
{   Serial.println(fail);}


Serial.print("Removing AA");
if(SD.rmdir("AA"))
{    Serial.println(success);}
else
{
    Serial.println(fail);
    Serial.print("Removing AA/BB/CC");
    if(SD.rmdir("AA/BB/CC"))
    {   Serial.println(success);}
    else
    {   Serial.println(fail);}

    Serial.print("Removing AA/BB");
    if(SD.rmdir("AA/BB"))
    {   Serial.println(success);}
    else
    {   Serial.println(fail);}

    Serial.print("Removing AA");
    if(SD.rmdir("AA"))
    {   Serial.println(success);}
    else
    {   Serial.println(fail);}
}


}

bool initializeSD()
{
  Serial.println("Initializing SD card...");
  if (!SD.begin(4)) {
    Serial.println("ERROR - SD card initialization failed!");
    return false;    // init failed
  }
  Serial.println("SUCCESS - SD card initialized.");
  // check for index.htm file
 
  return true;
}

Are you using SDFat or the one that comes standard with the IDE?

rmdir() From the SD (builtin) library requires indeed the directory to be empty (as documented)

For SDFat, have a look at this Post

I'm using the standard SD library version 1.1.1

Then you need to recursively (depth first) traverse all directory and remove files and then work your way back up cleaning up

I would recommend you move to SDFat… :slight_smile: (same author but improved compared to the builtin one - at the expense of a bit more complexity)

have a look at this Post regarding rmRfStar()