[SOLVED] Help in Storing SD card filenames in an Array of strings

need help about storing filenames of files in SD card. The filenames must be stored in an array of Strings for future use.
i've managed to print filenames in the serial monitor using the 'printDirectory' function, but i want to store them each in an array of String.

I have to display those filenames in 20x4 LCD, and add scrolling ability using my 4x4 keypad so i can scroll through filenames up and down. so i think it will be easier if i can store filenames in an array and use indexing to display them appropriately when scrolling up and down.

or do you have other ideas i can use aside from storing filenames in array?

thanks. =(

here's my code:

#include <SD.h>
#include <avr/pgmspace.h>

String plantName;
File plantDataFile, root;

int tempLimit=0, humidLimit=0, moistLimit=0, harvestLimit=0;

void setup(){
  Serial.begin(9600);
  pinMode(10, OUTPUT);
  
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

  //write to plant profile
  plantName = "romanian";
    //declare plant profile path
  String plantFile = "plants/" + plantName + ".txt";
  
  char plantNameCharArray[plantFile.length()];
  plantFile.toCharArray(plantNameCharArray, plantFile.length()+1);

writePlant(plantNameCharArray);
retrievePlant(plantNameCharArray); 
 
 
 root = SD.open("plants/");
 
 //print files inside plants directory
 printDirectory(root, 0);
 
 root.close();
}

void loop(){
}

void retrievePlant(char* plantNameCharArray){

  File plantDataFile = SD.open(plantNameCharArray);
  if(!plantDataFile){
    Serial.println("error opening, retrieve!");
  }  
  if(plantDataFile){
        Serial.println("retrieving plant profile");
	char temp[10];
	int x=0;
	int locator=0;
	while(plantDataFile.available()){

          char charRead = plantDataFile.read();
	  if(charRead=='\n'){
	    switch(locator){
              case 0:
              tempLimit = atoi(temp);
              break;
              case 1:
              humidLimit = atoi(temp);
              break;
              case 2:
              moistLimit = atoi(temp);
              break;
              case 3:
              harvestLimit = atoi(temp);
              break;
            }
	    locator++;
            for(int i=0; i<10; i++){
             temp[i]=' ';
            }
          x=0;
          continue;
          }
          if(locator==4){
            break;
          }
          temp[x]=charRead;
	  x++;
	}
	plantDataFile.close();
  }
  Serial.println(plantName);
  Serial.print("Temperature: ");
  Serial.println(tempLimit);
  Serial.print("Humidity: ");
  Serial.println(humidLimit);
  Serial.print("SoilMoisture: ");
  Serial.println(moistLimit);
  Serial.print("Harvest: ");
  Serial.println(harvestLimit);  
}

void writePlant(char* plantNameCharArray){
  SD.remove(plantNameCharArray);
  File plantDataFile = SD.open(plantNameCharArray, FILE_WRITE);

  if(!plantDataFile){
    Serial.println("error opening!, write");
  }
  if(plantDataFile){
        Serial.println("Writing to plant profile");
	plantDataFile.println("4");
	plantDataFile.println("6");
	plantDataFile.println("6");
	plantDataFile.println("1");
  }
 	
 plantDataFile.close(); 
}

void printDirectory(File dir, int numTabs) {
   while(true) {
     
     File entry =  dir.openNextFile();
     if (! entry) {
       // no more files
       //Serial.println("**nomorefiles**");
       break;
     }
     for (uint8_t i=0; i<numTabs; i++) {
       Serial.print('\t');
     }
     
     char* inString = entry.name();
     String stri = String(inString);
     stri = stri.substring(0, stri.length()-4);
     Serial.print(stri);
     
     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();
   }

}

An array would seem a reasonable method to hold the list of filenames but there will be a limit to how many you can hold due to memory limitations of the Arduino. Which board are you using ?

Are you sure that you need to store the names a Strings ? The advice from many here is to use C style strings (null terminated char arrays) instead but others favour usings Strings because of perceived ease of use. In your program you are already using both and convert between them, which does not seem sensible.

  String plantFile = "plants/" + plantName + ".txt";
  
  char plantNameCharArray[plantFile.length()];
  plantFile.toCharArray(plantNameCharArray, plantFile.length()+1);

writePlant(plantNameCharArray);
retrievePlant(plantNameCharArray);
     char* inString = entry.name();

This is where the name is being returned, as a pointer to some storage location. Make a copy of the pointed to data, in some other memory location, and store the pointer to that memory location in an array.

UKHeliBob:
An array would seem a reasonable method to hold the list of filenames but there will be a limit to how many you can hold due to memory limitations of the Arduino. Which board are you using ?

Are you sure that you need to store the names a Strings ? The advice from many here is to use C style strings (null terminated char arrays) instead but others favour usings Strings because of perceived ease of use. In your program you are already using both and convert between them, which does not seem sensible.

  String plantFile = "plants/" + plantName + ".txt";

char plantNameCharArray[plantFile.length()];
  plantFile.toCharArray(plantNameCharArray, plantFile.length()+1);

writePlant(plantNameCharArray);
retrievePlant(plantNameCharArray);

thanks for the advice. :slight_smile:

im using a board with ATmega 1281.

i have to convert it to C style strings because i get errors if i dont convert them.

i need to store them in array so i can get its length(no. of files) and manipulate and access each through indexing.

i tried to use

char* listOfFiles[30];

and store each filename in listOfFiles through indexing,

listOfFiles[x]=entry.name();

but as soon as i retrieve the elements of listOfFiles, they are all the same as the last filename stored.
its like this:

cabbage.txt
cabbage.txt
cabbage.txt
cabbage.txt
cabbage.txt
cabbage.txt

i also need to store those filenames in array so i can keep track of what to display in the LCD when the user presses scroll up or scroll down.

You are storing a pointer in each location in the array. The SAME pointer. You need to save, instead, what the pointer points to. That could be done using strdup(). Keep in mind that strdup() allocates memory, so you need to free that at some time.

It would be best NOT to do that, though. Any time you need to display file names, get the names. Do not copy them.

if you dont mind, can you give me example code on how to do it. thanks. :sweat_smile:

kamijean47:
if you dont mind, can you give me example code on how to do it. thanks. :sweat_smile:

Some snippets to show how each part is done:

char *ptrsToFileNames[20]; // Or however many you need to store

     ptrsToFileNames[n] = strdup(entry.name());

    free(ptrsToFileNames[n]);

thank you so much PaulS, its now working just as i want it. :stuck_out_tongue_closed_eyes:
but one more thing though,
can i dynamically resize the size of my char* array based on the elements i will store it into?
something like incrementing its size everytime i store something into it, rather than giving it a fixed size.
i want to use a for loop for displaying each item, something like

       for(int i=0; i<{char* filename's size}; i++){
         Serial.println(filename[i]);
       }

so, i wont bump into displaying empty lines.

can i dynamically resize the size of my char* array based on the elements i will store it into?

No
The size of the array is fixed but you could either keep a record of the number of filenames in the array as you store them or put a dummy value into the next array position each time you save a filename and stop when you get to that dummy value when displaying the filenames.

UKHeliBob:

can i dynamically resize the size of my char* array based on the elements i will store it into?

No
The size of the array is fixed but you could either keep a record of the number of filenames in the array as you store them or put a dummy value into the next array position each time you save a filename and stop when you get to that dummy value when displaying the filenames.

Even better would be to not use an array at all. Use a linked list. Each time you find a file, create a new node, store the file name in the node, and add the node to the linked list. A doubly linked list is not much more difficult, and can be traversed in both directions.

Don't forget to get the Arduino with a terabyte of memory, when you do this.

thanks for the help.
i just made a variable that will count how many filenames have been stored in the array.
:smiley:

in the end, i used strdup() to store filenames in the char* array

       //declared a global char* array
      char* plantList[20]; //i used maximum of 20 elements to be stored
      int listCounter=0; //variable to count how many filenames have been stored in the char* plantList
    
      //inside the function of listing all files
     char* temp = entry.name();
     String toString = String(temp); //converted filename to String
     toString = toString.substring(0, stri.length()-4); //made a substring to exempt the file extension(remove the *.txt)
     toString.toCharArray(inString, toString.length()+1); //converted it back to char array for it to be stored in char* plantList
     plantList[x]=strdup(inString);
     Serial.print(plantList[x]);
     listCounter++;

and now its flawLess.
Thank you very much for the help. :smiley: :grin: XD :stuck_out_tongue_closed_eyes: :wink: