Go Down

Topic: SdFat recursive File listing (Read 6724 times) previous topic - next topic

Rocktagon

The function LS didn't work for me so i try to build a recursive file list function by myself.
But it works not so fine.
It prints the first files, then prints the files from the first Directory but then Ends and i don't know why.

Code: [Select]
#include <SdFat.h>

const uint8_t chipSelect = 4;
SdFat sd;
SdFile file;

void pf(char *dir) {
  uint32_t pos = 0;
  Serial.print("*****");
  Serial.println(dir);
  sd.chdir(dir);
  char name[13];
  while (1) {
    sd.vwd()->seekSet(pos);
    if (!file.openNext(sd.vwd(), O_READ)) break;
    pos = sd.vwd()->curPosition();
    bool z = file.isDir();
    file.getFilename(name);
    Serial.println(name);
    file.close();
    if (z) pf(name);
  }
  Serial.println("-ende-");
}

void setup() {
  Serial.begin(115200);
  if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
  pf("\\");
}

void loop() {}
Non mihi non tibi sed nobis

fat16lib

#1
Aug 02, 2014, 03:22 pm Last Edit: Aug 02, 2014, 08:35 pm by fat16lib Reason: 1
Here is the problem.
Code: [Select]

 sd.chdir(dir);


This changes sd.vwd() to a different directory so the recursion will not work.  Your in the wrong directory when the recursive call returns.

You need to keep the state of the directory at every level.

That's why ls() does the recursion like this with an additional file, s.
Code: [Select]

     SdBaseFile s;
     if (s.open(this, index, O_READ)) s.ls(pr, flags, indent + 2);


I wrote ls() quickly a long time ago and should revisit ls().  I may do that soon since I am writing a new generic FAT filesystem that is not SD or Arduino dependent.

Rocktagon

Hm, ok. I thought with:

Code: [Select]
s.vwd()->seekSet(pos);
.....
pos = sd.vwd()->curPosition();


i go back to the old list pos.

I look if i can build it with your tip.
Thanks.
Non mihi non tibi sed nobis

fat16lib

#3
Aug 02, 2014, 08:22 pm Last Edit: Aug 02, 2014, 08:35 pm by fat16lib Reason: 1
This changes the file that sd.vwd() point to.
Code: [Select]

 sd.chdir(dir);


Restoring the position has no meaning since sd.vwd() now is a handle for "dir", not the file that you referenced with this.

Code: [Select]

 pos = sd.vwd()->curPosition();


You can not modify a global variable in a recursive function and have recursion work correctly.

What feature do you need in ls()?

fat16lib

Here is an ls() function like your pf().  It recursively list files in a subdir.
Code: [Select]

#include <SdFat.h>

const uint8_t SD_CHIP_SELECT = 10;
SdFat  sd;
//--------------------------------------------------------------
void ls(char *path) {
  SdBaseFile dir;
  if (!dir.open(path, O_READ) || !dir.isDir()) {
    Serial.println("bad dir");
    return;
  }
  dir.ls(&Serial, LS_R);
}
//-------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  if (!sd.begin(SD_CHIP_SELECT)) sd.errorHalt();
  sd.ls(&Serial, LS_R);
  Serial.println("Done with root");
  ls("DIR0");
  Serial.println("Done with DIR0");
}
void loop() {}


Here is output
Quote

A0.TXT
B0.TXT
DIR0/
  A1.TXT
  B1.TXT
  DIR1/
    A2.TXT
    B2.TXT
Done with root
A1.TXT
B1.TXT
DIR1/
  A2.TXT
  B2.TXT
Done with DIR0

Rocktagon

#5
Aug 02, 2014, 10:13 pm Last Edit: Aug 02, 2014, 10:28 pm by Rocktagon Reason: 1
It's just the beginning. Later i need an other format to communicate with a desktop Tool. At the moment i use the std SD Lib but i miss some functions like trunc and rename. So i try to change to the SdFat cause this has all the needed funcs. (whole project: http://www.rocktagon.de/forum/viewtopic.php?f=24&t=83 (german)).

At the moment i figure out this:

Code: [Select]
#include <SdFat.h>

const uint8_t chipSelect = 4;
SdFat sd;

byte pf(SdBaseFile s) {
 SdFile file;
 char name[13];
 while (1) {
   if (!file.openNext(&s, O_READ)) break;
   bool z = file.isDir();
   file.getFilename(name);
   file.close();
   if (z) Serial.print('\\');
   Serial.println(name);
   if (z) {
     SdBaseFile n;
     uint16_t index = s.curPosition() / 32 - 1;
     n.open(&s, index, O_READ);
     pf(n);
   }
 }
}

void setup() {
 Serial.begin(115200);
 if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
 SdBaseFile s;
 s.openRoot(sd.vol());
 pf(s);
}

void loop() {}


Works fine (thanks for your tip) but i searching a way to print the filenames with the wohle Directory path (output like: "\dir\dir\filename").
At last i need this output to a web client: "\dir\dir....\filename <size>"#10#13
Non mihi non tibi sed nobis

fat16lib

Hope your path will not be too deep if you have an Uno.  You are using a lot of memory on the stack for each level of recursion.

You will  need to maintain the path in a global variable as part of the recursion or maintain a list of pointers to each directory file in a global array. 

Rocktagon

#7
Aug 02, 2014, 11:27 pm Last Edit: Aug 03, 2014, 12:57 am by Rocktagon Reason: 1
My final solution (mybe not the best but it works):

Code: [Select]
#include <SdFat.h>

const uint8_t chipSelect = 4;
SdFat sd;

void pf(SdBaseFile s, char subdirs[][13], ArduinoOutStream outp, char dirnr = -1) {
  SdFile file;
  char name[13];                            // 8.3 format
  while (1) {
    if (!file.openNext(&s, O_READ)) break;  // no file - end
    bool z = file.isDir();
    file.getFilename(name);                 // File/directory name
    uint32_t fsize = file.fileSize();       // filesize
    file.close();                           // closing bevore open the next one
    if (z) {                                // add subdir and run new list
      memcpy(subdirs[dirnr + 1], name, strlen(name) + 1);
      SdBaseFile n;                         // new basefile for next directory
      uint16_t index = s.curPosition() / 32 - 1; //index of current directory
      n.open(&s, index, O_READ);            // open the directory
      pf(n, subdirs, outp, dirnr + 1);           // list files/directorys in this dir
    }
    else {                                  // print filename
      for (byte i = 0; i <= dirnr; i++)     // print all subdirectorys
        outp << (subdirs[i]) << '\\';
      outp << name << ' ' << fsize << "\n";
    }
  }
}

void printSDroot(ArduinoOutStream cout) {
  SdBaseFile s;
  char dircount[5][13];                     // max 5 subdirs
  s.openRoot(sd.vol());                     // open root dir
  pf(s, dircount, cout);
}

void setup() {
  Serial.begin(115200);
  if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
  printSDroot(ArduinoOutStream (Serial)); //Serial,Serial1,Serial2,client .... all who knows print
}

void loop() {}


p.s.: using 2560 and Due
Non mihi non tibi sed nobis

Go Up