Walking backwards in an SD directory

Status
Not open for further replies.

KG5NII

Member
I need a little help. My application is a T4.1 JPEG image slideshow application. I have implemented IR remote capability to not only change to next or previous album but also next photo and previous photo within an album. I define an album as a directory off the root of the SD Card:
Code:
001/
002/
003/
...
and so on.
Inside each album (directory) are jpeg files. Some albums have thousands of files.

Code:
001/
 1.jpg
 2.jpg
 3.jpg
 4.jpg
...
 n.jpg

and so on.


The issue:
Now opening the album and retrieving the next photo in the album:

Code:
File dir = SD.open("001");
while(true) {
    File photo = dir.openNextFile();
    if(!photo) break;
    ...
}

This is well and fine when walking forward in the album (directory). What I really need is something like an openPrevFile() method that will allow me to walk backwards in the directory from the current file backwards.

Looking at the openNextFile() code from the Teensy SD library:

Code:
// allows you to recurse into a directory
File File::openNextFile(uint8_t mode) {
  dir_t p;


  Serial.print("\t\treading dir...");
  while (_file->readDir(&p) > 0) {


    // done if past last used entry
    if (p.name[0] == DIR_NAME_FREE) {
      Serial.println("end");
      return File();
    }


    // skip deleted entry and entries for . and  ..
    if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') {
      Serial.println("dots");
      continue;
    }


    // only list subdirectories and files
    if (!DIR_IS_FILE_OR_SUBDIR(&p)) {
      Serial.println("notafile");
      continue;
    }


    // print file name with possible blank fill
    SdFile f;
    char name[13];
    _file->dirName(p, name);                //<<<<------------
    Serial.print("try to open file ");
    Serial.println(name);


    if (f.open(_file, name, mode)) {
      Serial.println("OK!");
      return File(f, name);    
    } else {
      Serial.println("ugh");
      return File();
    }
  }


  Serial.println("nothing");
  return File();
}

I think I get part of it. Something is incrementing p, I'm guessing it is the line _file->dirName(p, name); as denoted by the "//<<<<------------". The deal is, there has to be a really good reason why an openPrevFile() method doesn't exist. What am I missing here?

Can someone please offer some advice? I don't care if I have to patch the SD library, though this is a PITA, I've already had to do that by adding a directory file count method which could only offer good performance by adding the method to the library. I hate doing this, but it is what it is. Oh I've got this working by using calloc and creating a huge array of all the filenames as we openNextFile() through the directory. I hate this. it's ugly, it over complicates the code and I'm ashamed to even say I went this route. Some of the albums may contain over 5K jpeg files. There has to be a better more efficient way. How are others handling this?

Thanks for reading.
Ron, KG5NII
 
The problem with scanning a directory backwards is that a file has an variable number 32 byte entries and they are designed to be scanned in the forward direction. For example in exFAT the set count is in the first entry.

The SD card is designed to read forward. Buffers and caches in the card are designed for very large flash pages and the only way to go back a sector flushes these caches. You may need to scan the FAT from start of file to find the previous cluster.
 
Yes. Your explanation makes sense and now I know why such a method does not and will not exist in the SD library. That said then, it appears my original calloc(), recalloc() method of placing each filename in an array after a call to openNextFile() is not as dumb as I thought. I'm having issues when I calloc() fairly large blocks of memory, and then recalloc() that to a different size (when advancing to the next directory (album) on the SD Card. Eventually the Teensy will lock up. For some reason, trying to issue any kind of free() will make the Teensy very unhappy. However, recently I added 16M PSRAM but have yet to try that. All of this is the subject for a different thread. Thank you for taking the time to answer me.

Ron KG5NII
 
There is another possible solution. SdFat keeps an index that is used to update the directory entry. This can be used to open files.

Long ago I wrote an example using open by index to test the idea. I just tried it for exFAT and FAT and it still seems to work.

Look at this example and see if you could use the idea to get a openPrevFile.

Once the file is open you can print the file name but not the full path.

You can replace the sd and file types like this:
Code:
SdFs sd;
FsFile file;
FsFile dirFile;

Copy the test files to an SD and try it.
 
Status
Not open for further replies.
Back
Top