Read specific lines from txt file

Hi there..
I have txt file on SD card, the content of the file like this:

       M2
       # feep.uni
       24 7
       15
       0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
       0  3  3  3  3  0  0  7  7  7  7  0  0 11 11 11 11  0  0 15 15 15 15  0
       0  3  0  0  0  0  0  7  0  0  0  0  0 11  0  0  0  0  0 15  0  0 15  0
       0  3  3  3  0  0  0  7  7  7  0  0  0 11 11 11  0  0  0 15 15 15 15  0
       0  3  0  0  0  0  0  7  0  0  0  0  0 11  0  0  0  0  0 15  0  0  0  0
       0  3  0  0  0  0  0  7  7  7  7  0  0 11 11 11 11  0  0 15  0  0  0  0
       0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0

I need to skip the first two lines ( M2 and # feep.uni), and read the first, second, and third values (24 7 15) into a structure members ( int First; int Second; int Third;) .
sub->First = in_file.read(); //24
sub->Second = in_file.read(); //7
sub->Third = in_file.read(); //15

Then read the rest of values in 2D array.

The problem in this my code, I can not read to the values in correct way.
Can you help me to run my code correctly, please?

#include <stdio.h>
#include <stdlib.h>
#include <SD.h> 

#define MAX 100
struct fileinfostructure 
{
  int Third;
  int First;
  int Second;
  int data[MAX][MAX];
};

typedef struct fileinfostructure fileinfo;

void getfileinfo (char filename[], fileinfo *sub)
{
  File in_file;
  char ch;
  int row, col, type;
  int ch_int;

 if (!SD.begin(BUILTIN_SDCARD)) {
    Serial.println("Failed to mount card ");
  }
   in_file = SD.open(filename, FILE_READ);
  if (!in_file) {
    Serial.println("Opening file to read failed ");
  }

 ch = in_file.read();
  if(ch != 'M')
  {
     Serial.print("ERROR(1): Not valid type\n");
     exit(1);
  }

   in_file.read(); 
 
   while(in_file.read() != '\n');             /* skip to end of line*/
 
  while (ch = in_file.read() == '#')              /* skip comment lines */
  {
    while (in_file.read() != '\n');          /* skip to end of comment line */
  }

  in_file.seek(in_file.position());   

sub->First = in_file.read();
sub->Second = in_file.read();
sub->Third = in_file.read();

  Serial.printf("\n width  = %d",sub->First );
  Serial.printf("\n height = %d",sub->Second );
  Serial.printf("\n Third = %d",sub->Third);

     for (row=0; row < (*sub).Second; row++){
       for (col=0; col< (*sub).First; col++)
       {
         ch_int = in_file.read();
          if (ch_int < 0)
             Serial.printf("%d %d %d",row, col, ch_int);
          (*sub).data[row][col] = ch_int;
       }
     }
  
  in_file.close();
  Serial.println("\nDone reading file.\n");
}

void setup() {
  Serial.begin(9600);
  while (!Serial){}; 
  fileinfo *ss = (fileinfo*)malloc(sizeof(fileinfo));
  getfileinfo ("datafile.txt", &(*ss));  

}
void loop() {}

Are there non-printing characters like line end <cr> and/or <lf> in the file?

file.read() reads single characters, one-by-one, from the file.

What Arduino? an 800x800 array is too large for many of the smaller devices, including the Uno.

No, The file content exactly as I posted.

Yes,is too large, it just example.

Then what causes the line separation in what you posted?
BTW \n is a non-printing character, also identified as <lf>.

If those aren't present, you are stuck with counting characters to identify lines.

This structure implies line terminations. Which implies you can read each line and then parse it. Whereas, this would suggest no line terminations:

       M2 # feep.uni 24 7 15 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0

[/quote]

Please, do not edit your initial post. Instead, you could have simply said "100 instead of 800",
to which I would reply, "what processor are you using, because an Uno won't hold 100x100, either!"

Ok, I'll do that in next time :slight_smile: . I'm using teensy.

Then you're good. Sorry for the diversion!
Do we have an answer regarding line endings?

The line endings is \n .

I've no experience with SD cards, but I'd expect a function that allows you to read a line into a string buffer, where you can then parse it. So you'd simply read, read, read/parse, read/parse, and that should get you to the start of the 2D array.
Does that help?

Skip lines by reading characters until and including '\n'. The file.read() function inherits from the Arduino Stream class, and works just like Serial.read(), reading single characters at a time, or several into a predefined buffer.

The Arduino Serial Input Basics tutorial should be helpful.

@jremington
Is stream.readBytesUntil(character, buffer, length) not advised, then? Or is it not available on the teensy? I was about to suggest it.
Or, were you suggesting Serial for the examples, but expecting our OP to make the connection?

I personally don't find the Stream functions like readBytesUntil(), parseInt() etc. to be very useful, but they may work fine in this situation.

For serial UART streams they are blocking functions, which is pretty inconvenient, and there is no useful error handling.

Agreed, but in this use case... Unless the OP has other stuff going on which isn't exposed to us, there's no loss in blocking.

But yes, we are proposing a solution that is in general a poor coding practice.

In fact, I did not understand where I could use the proposed functions...but what about the while() in the code? Is it correct?

If you mean this while() loop, it should work to read to the beginning of the next line.

   while(in_file.read() != '\n');             /* skip to end of line*/

This won't skip a comment line. You need an "if" instead of the first while().

  while (ch = in_file.read() == '#')              /* skip comment lines */
  {
    while (in_file.read() != '\n');          /* skip to end of comment line */
  }

I have no idea what the following will do, or what is intended.

  in_file.seek(in_file.position());   

sub->First = in_file.read();
sub->Second = in_file.read();
sub->Third = in_file.read();

BE VERY CAREFUL with lines like this. Use parentheses to make your intention clear.

"==" has higher priority than "=".

  while (ch = in_file.read() == '#') 

These should read (24 7 15)
But these lines not worked.