finding Nth file on SD card ... works but only for a while

Hello !
i have modified the classic SD library “List Files” example, running on Arduino Mega, in order to first have a listing of all files on a SD card ; then have the name of the file number N on that SD card. It works, but only for a while as you can see hereunder.

here is my code :

#include <SPI.h>
#include <SD.h>

File entry;

int i, j  ;

void setup() {
  Serial.begin(9600);

  if (!SD.begin(53)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

  entry = SD.open("/");

  printDirectory(entry, 0);

  Serial.println("done!");
  Serial.println();
  entry.close();
}

void loop() {
  entry = SD.open("/");
  Serial.print("file");
  j = random(1, 10);

  Serial.print(String(j));
  Serial.print(":");
  Serial.println(NameFileNumber(entry, j));
  delay(1000);
}

String NameFileNumber(File & dir2, int a) {
  File entry2;
  dir2.rewindDirectory();
  for ( i = 0 ; i < a ; i++ ) {
    entry2 =  dir2.openNextFile();
    if (! entry2) {
      return ("EMPTY");
      break;
    }
  }
  return (entry2.name());
  entry2.close();
}

void printDirectory(File & dir, int numTabs) {
  while (true) {
    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      break;
    }

    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }

    Serial.print(entry.name());

    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }

    entry.close();

  }
}

i have this result, with a correct listing first, then some good results, then wrong ones :

initialization done.
CTK_7259.TXT		3742
QYB_8094.TXT		3742
XEL_6899.TXT		3742
PQT_9594.TXT		3800
ILD_3233.TXT		3800
SPM_8394.TXT		3800
DSW_1377.TXT		3939
ZYZ_1274.TXT		2030
JHJ_1299.TXT		1691
PMP_USB.INI		68
WINAMP~1.DAT		425
WINAMP~1.IDX		52
DCIM/
	108D5300/
SPM_83~1.TXT		3800
CTK_72~1.TXT		3742
QYB_80~1.TXT		3742
XEL_68~1.TXT		3742
ZYZ_12~1.TXT		2030
JHJ_12~1.TXT		1691
DSW_13~1.TXT		3939
ILD_32~1.TXT		3800
PQT_95~1.TXT		3800
SPM_83~2.TXT		3800
CTK_72~2.TXT		3742
QYB_80~2.TXT		3742
XEL_68~2.TXT		3742
ZYZ_12~2.TXT		2030
JHJ_12~2.TXT		1691
DSW_13~2.TXT		3939
ILD_32~2.TXT		3800
PQT_95~2.TXT		3800
done!

file5:ILD_3233.TXT
file8:ZYZ_1274.TXT
file6:SPM_8394.TXT
file3:XEL_6899.TXT
file5:ILD_3233.TXT
file9:JHJ_1299.TXT
file7:DSW_1377.TXT
file9:JHJ_1299.TXT
file9:JHJ_1299.TXT
file2:QYB_8094.TXT
file1:CTK_7259.TXT
file9:JHJ_1299.TXT
file7:DSW_1377.TXT
file9:JHJ_1299.TXT
file1:CTK_7259.TXT
file3:XEL_6899.TXT
file8:ZYZ_1274.TXT
file8:ZYZ_1274.TXT
file8:ZYZ_1274.TXT
file2:QYB_8094.TXT
file7:DSW_1377.TXT
file2:QYB_8094.TXT
file1:CTK_7259.TXT
file3:XEL_6899.TXT
file5:ILD_3233.TXT
file7:DSW_1377.TXT
file7:DSW_1377.TXT
file1:CTK_7259.TXT
file9:JHJ_1299.TXT
file8:ZYZ_1274.TXT
file8:ZYZ_1274.TXT
file3:XEL_6899.TXT
file6:SPM_8394.TXT
file2:QYB_8094.TXT
file9:EMPTY
file1:EMPTY
file2:EMPTY
file2:EMPTY
file1:EMPTY
file4:EMPTY
file2:EMPTY
file3:EMPTY
file2:EMPTY
file1:EMPTY
file3:EMPTY
file3:EMPTY
file3:EMPTY
file5:EMPTY
file7:EMPTY
file5:EMPTY
file9:EMPTY
file3:EMPTY
file8:EMPTY
file2:EMPTY
(and so on)

i saw several problems on the forum close to this one, but tried the propositions : closing the files, rewinding the directories, using & or *, without any positive results. is there a way out of this with SD.h or should i rewrite using SdFat ? Where is it basically going wrong ?

  Serial.print(String(j));

EVERY Arduino knows how to print an integer value to the serial port as a string. NONE of them need your ham-fisted assistance to convert the int to a string and wrap the string in a String instance that it then needs to unwrap to get the string to print.

      return ("EMPTY");
      break;
    }
  }
  return (entry2.name());

Neither "EMPTY" or entry.name() are a String. There is no reason to piss away resources wrapping the strings in String instances. This function should return a char pointer. The value in entry.name() will need to be copied into a static string that the function owns, so that the memory does not go out of scope, rendering the pointer useless.

It works, but only for a while

When you quit pissing away memory using Strings, it will work forever.

thanks for pointing me the problem !

i have found this that might be useful : The Evils of Arduino Strings | Majenko's Hardware Hacking Blog

  return (entry2.name());
  entry2.close();

The close will never be executed but perhaps it isn't needed, in which case delete that statement.

Pete

tried not “pissing away memory with strings”, but the problem stays…
the function works perfectly for a while ( about 40 iterations ) then goes wrong.

#include <SPI.h>
#include <SD.h>

File entry, entryz;

int i, j  ;

void setup() {
  Serial.begin(9600);

  if (!SD.begin(53)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
 
}

void loop() {
 entry = SD.open("/");
  Serial.print(F("file"));
  j = random(1, 4);

  Serial.print( j );
  Serial.print(F(":"));
  NameFileNumber(entry, j) ;
  delay(100);
  entry.close();
}

void NameFileNumber(File dir2, int a) {
  for ( i = 0 ; i < a ; i++ ) {
     entryz =  dir2.openNextFile();
    if (!entryz) {
      entryz.close();
      Serial.print(F("empty"));
      break;
    }  
  }
  Serial.print(i);
  Serial.print(":");
  Serial.println(entryz.name());
  
    entryz.close();
}

result looking like this :

file1:1:HJR_9217.TXT
file1:1:HJR_9217.TXT
file2:2:XZP_5597.TXT
file3:3:CEK_7965.TXT
file3:3:CEK_7965.TXT
file2:2:XZP_5597.TXT
file1:1:HJR_9217.TXT
file2:2:XZP_5597.TXT
file3:3:CEK_7965.TXT
file3:3:CEK_7965.TXT
file3:3:CEK_7965.TXT
file1:1:HJR_9217.TXT
file1:1:HJR_9217.TXT
file2:2:XZP_5597.TXT
file2:2:XZP_5597.TXT
file1:1:HJR_9217.TXT
file2:empty1:HJR_9217.TXT
file3:empty0:/
file3:empty0:/
file1:empty0:/
file1:empty0:/
file2:empty0:/
file2:empty0:/
file1:empty0:/
file1:empty0:/
file2:empty0:/
file2:empty0:/
file3:empty0:/
file3:empty0:/
file2:empty0:/

since i couldnt resolve the problem with the initial sketch, i redid the whole thing from an example using SdFat instead of SD.
it now works perfectly…

#include <SPI.h>
#include "SdFat.h"

// SD default chip select pin.
const uint8_t chipSelect = SS;

int i, j = 0 ;

SdFat sd;
SdFile file;

char name[80];
int nameLen = 40;

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.print(F("file"));
  j = random(1, 10);
  Serial.print( j );
  Serial.print(F(":"));
  NameFileNumber(j) ;
  Serial.println(name);
}

void NameFileNumber( int a) {

  if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
    sd.initErrorHalt();
  }

  sd.vwd()->rewind();

  for ( i = 0 ; i < a ; i++ ) {

    if (!file.openNext(sd.vwd(), O_READ))
    {
       strcpy(name, "Empty");
      break;
    }  else {

      if ( i == (a - 1) )  {
        file.getName(name, nameLen);

        if (file.isDir()) {
                Serial.write('/');
        }
  
      }

      file.close();
    }
  }

}