How to check if it is a directory?

Hello. In the standard examples of working with the file system, there is an example of listing files with their sizes. Here he is (Filesystem — ESP8266 Arduino Core 3.1.1-26-g734defb8 documentation):

Dir dir = LittleFS.openDir("/");
while (dir.next()) {
    Serial.print(dir.fileName());
    if(dir.fileSize()) {
        File f = dir.openFile("r");
        Serial.println(f.size());
    }
}

But, if there is a directory and files in it, then this example cannot determine that this is a directory and even shows its size as zero. In theory, it would be possible to insert a check whether it is a directory or not. It seems to be used for this:

isDirectory
bool amIADir = file.isDir();

But I don't understand how. Can someone tell me how to check correctly?
Alternatively, I tried it like this:

Dir dir = LittleFS.openDir("/");
while (dir.next()) {
    Serial.print(dir.fileName());
      if(dir.fileName() isDirectory){ // in theory, this would check if the name/file is a directory
        Serial.println(String(dir.fileName())+" is a directory");
      }
      else {
        File f = dir.openFile("r");
        Serial.println(f.size());
      }

Hi @dyadyagenya ,

did you try something like this:

Dir dir = LittleFS.openDir("/");
while (dir.next()) {
    Serial.print(dir.fileName());
    if(dir.fileSize()) {
        File f = dir.openFile("r");
        Serial.print(f.name());
        if  ( f.isDir() ) {
             Serial.println(" is a directory");
          } else {
             Serial.println(" is a file");
         }
    }
}

Haven't checked or compiled it but the general information is that

.isDir()

is a method of the object file.

So you have to open a file and then you can use its method ...

ec2021

I tried something similar. And the errors are similar. Taking your example, it produces the following:
Compilation error: 'class fs::File' has no member named 'isDir'

I solved this problem like this:

Dir dir = LittleFS.openDir("/");
while (dir.next()) {
      if(dir.isDirectory()){ // in theory, this would check if the name/file is a directory
        Serial.println(String(dir.fileName())+" is a directory");
      }
      else {
        Serial.print(dir.fileName());
        File f = dir.openFile("r");
        Serial.println(f.size());
      }
  }

Now I can't figure out how to make the code check the files in the directory, that is, something like recursion, to scan all the folders and files in them.

Did you try to use file.isFile()?

If it is not, it should be a directory...

Anyway, there is something strange if you use LittleFs because it surely provides these functions.

I can have a look earliest this evening...

ec2021

Yes, I tried, but it still works for me if I write the name of the directory and its nesting levels myself. But I would like to scan to the full depth of the nesting.

Even if I manage to do it myself, I will be glad for your option to scan the entire depth of the catalog.

I recommend that you post the full code, otherwise it is more or less guesswork to find the reason for the problem ... In minimum it would be helpful if you post a sketch that contains all necessary parts where you encountered the problem and compiles.

If you are looking for a code that iteratively prints the content of directories you might easily google for

printDirectory Wokwi

and you will find an example on Wokwi which you might adapt to your needs!

I do not like to copy it into the Arduino forum as it is a Wokwi example and does not belong to me ...

And there is also a very comprehensive explanation how to use SD cards here

https://wolles-elektronikkiste.de/en/sd-cards-and-sd-card-modules

It looks as if the documentation you linked in your first post refers to a different implementation of LittleFS as it describes ".isDir()" instead of ".isDirectory()". This would also explain why (on gitHub at https://github.com/esp8266/Arduino/blob/master/libraries/LittleFS/src/LittleFS.h one will find the implemenation of ".isFile()" while you get a compilation error ...

ec2021

I also had similar suspicions. I didn't seem to include any additional libraries. I used the ones that come with the esp8266 board. That is, what is described on the official espressif page.

We can find many things on the Internet. But I'm learning and therefore I would like to understand myself using hints. Later, when I understand the basics, I can also analyze and use other people's examples.

The complete code is quite simple:

#include <FS.h>
#include <LittleFS.h>

String path = "/";

void setup() {
Serial.begin(74880);
if(LittleFS.begin()) {
  delay(1000);
  Serial.println("Initialised OK");}

scan_dir(path);
}

void scan_dir(String){
Dir dir1 = LittleFS.openDir(path);
while (dir1.next()) {
      if(dir1.isDirectory()){
        Serial.println(String(dir1.fileName())+" is a directory");
Serial.println("??? "+path+String(dir1.fileName()));
// scan_dir(path+String(dir1.fileName())); // Here I try to do a recursion for a full directory scan
      }
      else {
        Serial.print(dir1.fileName());
        File f = dir1.openFile("r");
        Serial.println(f.size());
      }
  }
}

Thanks ... Actually loop() {} is still missing ...

My problem is that I do not have any 8266 but some ESP32. However the littleFS libs for ESP32 work different. So I cannot test your implementation.

Feel free to test this (just checked on theoretical level ... ):

#include "FS.h"
#include <LittleFS.h>

String path = "/";

void setup() {
  Serial.begin(74880);
  if (LittleFS.begin()) {
    delay(1000);
    Serial.println("Initialised OK");
  }
  scan_dir(path);
}

void loop(){

}

void scan_dir(String path) {
  Dir dir1 = LittleFS.openDir(path);
  while (dir1.next()) {
      if (dir1.isFile()){
        Serial.print("File:\t");
        Serial.print(path + dir1.fileName());
        Serial.print("\tSize:\t");
        if (dir1.fileSize()){
          File f = dir1.openFile("r");
          Serial.println(f.size());
          f.close();
        } else {
          Serial.println("0");
        }  
      }
      if (dir1.isDirectory()) {
        Serial.print("Dir:\t")
        Serial.println(path+dir1.fileName()+"/");
        scan_dir(path+dir1.fileName()+"/"); //  Recursion for a full directory scan
      }
  }
}

The ESP32 example for littleFS uses this recursive function:

void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
    Serial.printf("Listing directory: %s\r\n", dirname);

    File root = fs.open(dirname);
    if(!root){
        Serial.println("- failed to open directory");
        return;
    }
    if(!root.isDirectory()){
        Serial.println(" - not a directory");
        return;
    }

    File file = root.openNextFile();
    while(file){
        if(file.isDirectory()){
            Serial.print("  DIR : ");
            Serial.println(file.name());
            if(levels){
                listDir(fs, file.name(), levels -1);
            }
        } else {
            Serial.print("  FILE: ");
            Serial.print(file.name());
            Serial.print("\tSIZE: ");
            Serial.println(file.size());
        }
        file = root.openNextFile();
    }
}

This might also work with your version; the function is called like this

  listDir(LITTLEFS, "/", 3);

Where the second parameter names the start directory (here root -> "/" ) and the third parameter determines the number of directory levels allowed to be scanned (to limit the recursions).

If my suggestions don't work you'd better find someone with the same hardware setup who has experience with this library ... :wink:

Good luck
ec2021

1 Like

This works great. And I even understood my problem))) Specially double-checked. In my opinion, I wrote the arguments incorrectly in the function. It seemed to me that I only needed to specify the data type, not the data type along with the variable name. That is, my mistake apparently was in this line:
void scan_dir(String path) {
In your opinion, can I get the size of a directory using some standard function, or do I need to organize the calculation of the size of files inside the directory?

and:

Unfortunately this produces the following error:
Compilation error: LITTLEFS.h: No such file or directory
I tried to write the name of the LittleFS library. I thought that the esp8266 library was so different from esp32, but the error remained. Can you tell me which library you used for this?
Or maybe some other additives are needed somewhere else in the sketch?

I'm glad that the (untested) suggestion works :slight_smile:

This is where you find LittleFS for ESP32:

https://github.com/lorol/LITTLEFS

and the listDir() function can be found (line 16ff ) in

https://github.com/lorol/LITTLEFS/blob/master/examples/LITTLEFS_test/LITTLEFS_test.ino

The ESP32 example might probably work if you modify it, but I am not sure because there are quite a number of differences between the implementations!

Just a try out of curiosity:

void listDir(const char * dirname, uint8_t levels){
    Serial.printf("Listing directory: %s\r\n", dirname);

    File root = fs.open(dirname);
    if(!root){
        Serial.println("- failed to open directory");
        return;
    }
    if(!root.isDirectory()){
        Serial.println(" - not a directory");
        return;
    }

    File file = root.openNextFile();
    while(file){
        if(file.isDirectory()){
            Serial.print("  DIR : ");
            Serial.println(file.name());
            if(levels){
                listDir(file.name(), levels -1);
            }
        } else {
            Serial.print("  FILE: ");
            Serial.print(file.name());
            Serial.print("\tSIZE: ");
            Serial.println(file.size());
        }
        file = root.openNextFile();
    }
}

I removed "fs::FS &fs" ... Serial.printf() should work with ESP8266 as with ESP32 ...
If it doesn't work -> put in in the bin :wink:

Regarding the size of files in a directory I have not found a "standard function"; I am afraid that's up to you to realize.

Again not tested but you may try this

unsigned long dirSize(String path){
  Dir myDir = LittleFS.openDir(path);
  unsigned long myDirSize = 0;
  while (myDir.next()) {
      if (myDir.isFile()){
        myDirSize += myDir.fileSize();
     }
  }   
  return myDirSize;
}

// Use:     Serial.println(path + "\t Size = " + String(dirSize(path));

Just feed it with different paths to your filesystem. If it works, you could place it just before the recursive call to scan_dir(). Not the most efficient way but it should do it. I hope no typos or missing brackets etc. ...

ec2021

P.S.: If the dirSize function works you can also simplify the scan_dir function:

// Replace this 
/*
 if (dir1.fileSize()){
         File f = dir1.openFile("r");
         Serial.println(f.size());
         f.close();
        } else {
          Serial.println("0");
*/
// By this
     Serial.println(dir1.fileSize());
1 Like

Apparently I didn't express myself correctly. I meant how I can then figure out which library is which. They are both named LITTLEFS.h. If I understand correctly, if I put the library you gave the link to, will it automatically connect if the esp32 board is selected or do I need to somehow connect in a special way so that the one that comes with esp8266 does not connect instead?

I will try tomorrow

I used it like this:

      if (dir1.isDirectory()) {
        Serial.print("Dir:\t");
        Serial.print(path+dir1.fileName()+"/");
        Serial.print("\t\tSize:\t");
        Serial.println(dirSize(path+dir1.fileName()+"/"));
        scan_dir(path+dir1.fileName()+"/"); //  Recursion for a full directory scan
       }

But there is a problem in this form. Let's say the directory contains three subdirectories and 5 files, not counting those that are in subdirectories. In this form, the function counts only the files that are in the directory, not taking into account those that are in subdirectories. That is, it will calculate only the sum of five files.
And the second small problem is that it does not count the volume of files in the root directory. It doesn't matter if it's really the topmost directory or one of its nested ones. The root directory from which there is a countdown in this form does not count yet.
But I will think about it tomorrow.

So I understand it works for a given directory, ok?

Then if you want to know the aggregated size of a directory plus it's subs, the function needs to become iterative (like scan_dir()) ...

Isn't that a nice exercise? :slight_smile:

ec2021

Regarding the libraries you can

  • open Arduino IDE and open the Preferences dialog
  • Look where your sketch folder is placed
  • Open that folder in a Browser

Then you should see a folder "libraries".
Open that again and search for a folder "LittleFs" ...
In that folder you will find the lib that your IDE is using if it has been downloaded correctly.

Other places are where the hardware specific libs are stored.

ec2021

For a given directory, it only counts the sum of the files, but does not add the sum of nested subdirectories.

I understand that recursion is needed.

Nice. But so far it doesn't work for me.

By the way, I do not understand why it was necessary to use it? I changed to:
Serial.println(dir1.fileSize());
That is, this piece of code looks like this:

      if (dir1.isFile()){
        Serial.print("File:\t");
        Serial.print(path + dir1.fileName());
        Serial.print("\tSize:\t");
        Serial.println(dir1.fileSize());
      }

And it prints everything the same as in your version. Or am I missing some difference?

I am not sure what your question is about ...

This is the change I suggested (it makes open and close of files obsolet and should therefore be quicker:

#include "FS.h"
#include <LittleFS.h>

String path = "/";

void setup() {
  Serial.begin(74880);
  if (LittleFS.begin()) {
    delay(1000);
    Serial.println("Initialised OK");
  }
  scan_dir(path);
}

void loop(){

}

void scan_dir(String path) {
  Dir dir1 = LittleFS.openDir(path);
  while (dir1.next()) {
      if (dir1.isFile()){
        Serial.print("File:\t");
        Serial.print(path + dir1.fileName());
        Serial.print("\tSize:\t");
        Serial.println(dir1.fileSize());    // No need to open and close the file to get its size
      }
      if (dir1.isDirectory()) {
        Serial.print("Dir:\t")
        Serial.println(path+dir1.fileName()+"/");
        scan_dir(path+dir1.fileName()+"/"); //  Recursion for a full directory scan
      }
  }
}

I thought it might be a good exercise for you to make it recursive ... :wink:

ec2021

It is not quite clear if you want it

  • to add the size of one directory and the size of all its subdirectories
    or
  • to display the size of each directory separately

The later is easier to achieve ...

and

I understand correctly that my variant will run slower, so you used your variant?

Yes, at the moment I'm not in a hurry, so I can afford to devote more time to solving the problem. But so far I haven't got it.

The size of each directory and the size of the starting directory from which the scan starts.