List File Structure in Arduino

List File Structure in Arduino

"Often, your project may involve saving data in the file system while performing normal operations, such as creating directories and creating, writing, appending to, or deleting files. To keep track of these files and directories, you need a way of organising them. I will show you my way using Arduino JSON."

Gideon Maina

Gideon Maina

Senior IoT Engineer

September 16, 2025
3 min read

Getting started

The presumption before moving forward is that you have already set up your FS instance whether it is SPIFFS, LittleFS or SD. Also, basic knowledge of JSON objects is a requisite.

Install the ArduinoJSON to your project: I used v7 at the time of writing this.

The Code

  1. Create a JsonDocument object like JsonDocument doc. This will hold the overall JSON object.

  2. Create a general-purpose polymorphic function wrapper that accepts a String reference and JsonObject reference as parameters. The function will return nothing void.
    std::function<void(const String &, JsonObject &)> listDir; - listDir is our variable for the function template.

  3. Assign listDir to a function. I will use a lambda expression of this case.
    listDir = [&](const String &path, JsonObject &obj){}

    • [&] captures any variables from the surrounding scope by reference.

    • The function accepts a string that represents the path of interest in your file system and a JsonObject.

  4. Adding functionality to the function.

 listDir = [&](const String &path, JsonObject &obj)
    {
        File dir = fs.open(path);
        if (!dir || !dir.isDirectory())
            return;
        File file = dir.openNextFile();
        while (file)
        {
            String name = file.name();
            if (file.isDirectory())
            {
                JsonObject subdir = obj[name].to();
                // Build the full path for recursive call
                String fullPath = path;
                if (!path.endsWith("/"))
                {
                    fullPath += "/";
                }
                fullPath += name;
                listDir(fullPath, subdir); // Use full path instead of just name
            }
            else
            {
                obj[name] = "file";
            }
            file = dir.openNextFile();
        }
    };    

The function performs some checks to determine if the path is a directroy or not and continues to open the next file if true; this is essential for the root directory at the beginning of the function call. The while loop is for recursively calling listDir for nested directories or assign the value "file" to the key if otherwise (the key is the name of the file/directory).

Putting everything together

Nest this in a function that either prints the file structure or returns a string representation. Returning a JsonDocument would also work depending on your use-case.

static String listFiles(fs::FS &fs)
{
    JsonDocument doc;

    std::function listDir;
    listDir = [&](const String &path, JsonObject &obj)
    {
        File dir = fs.open(path);
        if (!dir || !dir.isDirectory())
            return;
        File file = dir.openNextFile();
        while (file)
        {
            String name = file.name();
            if (file.isDirectory())
            {
                JsonObject subdir = obj[name].to();
                // Build the full path for recursive call
                String fullPath = path;
                if (!path.endsWith("/"))
                {
                    fullPath += "/";
                }
                fullPath += name;
                listDir(fullPath, subdir); // Use full path instead of just name
            }
            else
            {
                obj[name] = "file";
            }
            file = dir.openNextFile();
        }
    };

    JsonObject root = doc.to();
    listDir("/", root);
    // serializeJsonPretty(doc, Serial); // debug

    String file_list;
    serializeJsonPretty(doc, file_list);
    Serial.println(file_list);
    return file_list;
}

The function accespts an FS instance and JsonObject reference to the JsonDocument object, and calls the listDir function with the root path "/". The function returns a serialized JSON string. You can modify the function to accept a starting path as parameter.




Example output

Screenshot 2025-09-03 at 14.43.59.png
Screenshot 2025-09-03 at 14.43.59.png

This is the output of the file structure I used in an ESP32 webserver project.
Gideon Maina

About Gideon Maina

Senior IoT Engineer

IoT Engineer and Full-stack Developer passionate about building innovative solutions for African challenges. Experienced in sensor networks, web development, and data visualization.