
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
Senior IoT Engineer
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
Create a JsonDocument object like
JsonDocument doc
. This will hold the overall JSON object.Create a general-purpose polymorphic function wrapper that accepts a
String
reference andJsonObject
reference as parameters. The function will return nothingvoid
.
std::function<void(const String &, JsonObject &)> listDir;
-listDir
is our variable for the function template.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.
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


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.