Arduino: read a specific line from SD card

I have a problem reading a specific line in a file from the SD card. The only thing I can do is display all text written in file to the serial monitor. How can I read a specific line, for example line 3 or 5.
here are the text written in order inside file "Sample.txt"
1
2
3
4
5

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

const int CSpin = 10;

File myFile;

void InitializeSDcard();

void setup(){
 pinMode(CSpin, OUTPUT);
 Serial.begin(9600);
 InitializeSDcard();
 
 //open a file
 OpenFile("Sample.txt");
 while (myFile.available()) {
 String list = myFile.readStringUntil('\r');
 Serial.println(list);
 }
}

void loop(){

}
void InitializeSDcard(){
  Serial.println("Opening SD Card . . .");
  delay(500);
  if(SD.begin(CSpin))
  {
    Serial.println("SD Card ready to use");
  }else{
    Serial.println("Failed to open SD Card");
    return;
  }
}

int OpenFile(char Filename[]){
  myFile = SD.open(Filename, FILE_WRITE);
  myFile = SD.open(Filename, FILE_READ);
  delay(500);
  if(myFile)
  {
    Serial.println("File is open");
    return 1;
  }else{
    Serial.println("Error opening file");
    return 0;
  }
}

How can I read a specific line, for example line 3 or 5.

First, you need to define what "a specific line" means. The file you are reading is a stream of bytes. The functions you are using have no concept of "a line".

You might read and store all the data until a specific value, like '\n' or '\r' is read. When the end of record marker is read, increment a counter. If the counter has the desired value, use the stored data. If not, reset the buffer and index and keep reading.

It would be better to NOT use the String class or any functions that return Strings. But, if you insist, then it is simple to count the lines as you read them (using readStringUntil()), and do something when the count matches the value of interest.

The only way to start reading, in the file, at record n is to have fixed length records where you know the length.

Sir can you give me a sample code of that?
explaining each line of code if possible. thank you :slight_smile:

 int recNum = 0; // We have read 0 records so far

 //open a file
 OpenFile("Sample.txt");

 while (myFile.available())
 {
    String list = myFile.readStringUntil('\r');
    Serial.println(list);
    recNum++; // Count the record

    if(recNum == recordNumberOfInterest)
    {
       // Hey, we found the one that we want to do something with
    }
 }

Most of this, with the exception of formatting it properly, is taken directly from your post.

Correct me if Im wrong, will this code still work even if I have 20k number of lines in a single file?. How much memory can the arduino take? Ive read some post about their arduino crashing because of ow memory. Or maybe my understanding with this is wrong. sorry im new to these type of things. Bare with me

And what is exactly the difference between '\r' and '\n'. When can I use or the perfect time I can use those?

If the lines are different length you just need to search the lines

void printLineN(unsigned int lineNumer){
  myFile.seek(0);
  char cr;
  
  for(unsigned int i = 0; i < (lineNumber -1);){
    cr = MyFile.read()
    if(cr == '\n'){
      i++;
    }
  }
  
  //Now we are at the right line
  while(true){
    cr = myFile.read();
    Serial.write(cr);
    if(cr == '\n'){
      break;
    }
  }
  //a for loop with a read limit might be a good idea
}

If the lines are fixed length you could seek() to the right position

myFile.seek(lineNumer * LineLength);

All texts have the same length. I have also read about putting a marker(for example the ",") at every end of the line. How can I read the 3rd line by searching the 3rd comma?

A comma or a new line char make no difference. See my example.

But if all line have the same length, see my second example. That really makes things easier and will be WAYYYYYY faster.

will this code still work even if I have 20k number of lines in a single file?

Yes, though it will not be fast.

How much memory can the arduino take?

Take is the wrong term. Have is correct. The amount of memory that an Arduino has depends on which type it is. The 328-based Arduinos, such as the UNO, have 2K bytes of SRAM.

Bare with me

I'll keep my clothes on. But, you go ahead. Post pictures, if you dare.

And what is exactly the difference between '\r' and '\n'.

Ever seen a typewriter? One moves the carriage back and forth. The other advances the carriage by one position. Otherwise known as carriage return and line feed.

All texts have the same length.

I can not imagine, given your example and questions, how. After line 9, the next record would contain '1', '0', '\n', and '\r'. After line 99, the next record would contain '1', '\0', '0', '\n', and '\r'. Records 1, 10, 100, 1000, and 10000 will all have different lengths. Unless your real data looks nothing like your example data.

If your records ARE all the same length, you can go to the start of record n using seek((n-1) * recordLength).

Thank You PaulS.. Your first sample code worked perfectly!! :smiley:

septillion:
If the lines are different length you just need to search the lines

void printLineN(unsigned int lineNumer){

myFile.seek(0);
  char cr;
 
  for(unsigned int i = 0; i < (lineNumber -1);){
    cr = MyFile.read()
    if(cr == '\n'){
      i++;
    }
  }
 
  //Now we are at the right line
  while(true){
    cr = myFile.read();
    Serial.write(cr);
    if(cr == '\n'){
      break;
    }
  }
  //a for loop with a read limit might be a good idea
}




If the lines are fixed length you could seek() to the right position


myFile.seek(lineNumer * LineLength);

So myFile.seek(3)

Will get the value of the 3rd line of the text file? Am i right?

projectdimpreza:
So myFile.seek(3)

Will get the value of the 3rd line of the text file? Am i right?

No, seek function by itself returns a boolean if it is succesful.
Calling myFile.seek(3) will move your position in the file of 3 characters: you have to multiply it for the number of characters in a line like septillion did (assuming the lines have fixed length) in order to position yourself at the beginning of the third line (starting from 0).

No, seek function by itself returns a boolean if it is succesful.
Calling myFile.seek(3) will move your position in the file of 3 characters: you have to multiply it for the number of characters in a line like septillion did (assuming the lines have fixed length) in order to position yourself at the beginning of the third line (starting from 0).

I have a text file containing this:

10
20
30
40
50

And i want to read the 3rd line which is "30"

myFile.seek(3*2) ?

Is this right?

Is this right?

Possibly a trick question, but how many bytes are there on each line ?

Possibly a trick question, but how many bytes are there on each line ?

I gues 2 bytes each line..

Check sample text file..

10
20
30
40
50

projectdimpreza:
I gues

Guessing's never good :wink:

Why don't you open the file with the hex dump utility in #4 here and have a good look inside?

projectdimpreza:
I gues 2 bytes each line..

Check sample text file..

10
20
30
40
50

Wrong I am afraid

What do you think marks the end of each line ?

UKHeliBob:
Wrong I am afraid

What do you think marks the end of each line ?

\n

But i dont really understand.. could u explain im a new to this things.

Possible line endings are \r, \n or \r\n. It depends on the application that created the file.

So e.g. 10\r\n counts as four characters.

sterretje:
Possible line endings are \r, \n or \r\n. It depends on the application that created the file.

So e.g. 10\r\n counts as four characters.

\r \n is same as cr lf?

Could u tell me which is cr and which is lf?

So if 10\r\n counts for characters..

And if the text file is like this..

10
20
30
40
50

I will use myFile.seek(1*4). ??

Because 1 is the first line and 4 is the number or characters?