How to get the last counter value from txt file from SD card

Hello everyone!

I try to count impulses from water meter.
I also attached an Sd card to Arduino Nano to backup counts.

The text file is like this (4 digits):

5742,
5743,
5744,

The code for writing the counts is:

myFile.print(buttonPresses1);
     myFile.println(",");
     // myFile.print(buttonPresses1);       // printing without <CR>

I added this “,” comma sign while struggling within, it’s not that necessary. I also tried .

If the Arduino is out of the power, I need to read the LAST count to continue with.

I tried this code to get the last line:

File dataFile = SD.open ("cold.txt", FILE_READ);
if (dataFile) 
  {
    while (dataFile.available())
    {
      String  line = dataFile.readStringUntil(','); 
      lcd.print(line);
      Serial.print(line);
//      delay(10);
    }
Serial.println("The last line is  ");    
Serial.println(line);
lcd.print("The last line is  ");    
lcd.println(line);    

    dataFile.close();

}
}

The problem is - I can see the whole counts in comport monitor as well as on LCD. But I could not get this LAST digit to work with. I need to setup the initial starting point for the meter after power failure.

Comport Monitor says:

Initializing SD-card...
5739
5740
5741
5742
5743
5744
The last line is

Could anyone help me out with this issue?
Kindly appreciated in advance!
Thank you,
Dmitry

You could try to use seekEnd to position to the last number

datafile.seekEnd(-7); // 5 chars + cr + lf

Sorry, could not compile the sketch

SD_card_RW_test:67: error: 'class SDLib::File' has no member named 'seekEnd'

      String line = dataFile.seekEnd(-7);            // 5 chars + cr + lf

                             ^

exit status 1
'class SDLib::File' has no member named 'seekEnd'

Is there a way to use that String, which I get?
Or, the last value of "line" is empty? Why I cannot see it after the "The last line is "

The SdFat library I'm using has that functionality, I did not regard it special, sorry.

You should be able to use something like the following for the positioning.

dataFile.seek(dataFile.size()-7);

Thank you!

I have figured it out, no problem. But still have the same problem.

I installed the SdFat library, have a lot of inclused added. But I use the stanard SD library to work with SD card, I suppose now it conflicts with SdFat. I have got a lot of errors.

What I could not understand - why the LAST value is ?
I tried this, reading the string until “,” and converting the string into integer.

String  line_str = dataFile.readStringUntil(','); 
          int line = line_str.toInt();
          Serial.print(line);

I tried to remove “\n” in the incoming text file like this:

5739,5740,5741,5742,5743,5744,

The parsing works perfectly, except the last value while I’m out of “while” cycle.

What I am doing wrong?

Thanks

The way you are reading (up to a ',' and then checking for available()) always gives you a cr-lf as the last line.

I would position to the interesting 4 characters and read them to a buffer, or convert them directly to an int.

Thank you for your help.
I suppose I have found the solution.

As I figured out, the last line always should be "0"
So what I needed to get was the previous value.

I did this code and looks like it works:

File dataFile = SD.open ("cold.txt", FILE_READ);
if (dataFile) 
  {
    while (dataFile.available())
    {
      String  line_str = dataFile.readStringUntil(',');  // string lavue reading from the stream - from , to , (coma to comma) 
      int line = line_str.toInt(); 
          if (line != 0)                                // checking for the last NON-Zero value
              {
                 line2 = line;                          // this really does the trick
              }
      
      // String  line = dataFile.readString(); 
      // lastline = dataFile.parseInt();

      lcd.print(line2);
      Serial.print(line2);
      delay(100);
    }
    lcd.clear();
Serial.print("Last line = ");    
Serial.print(line2);
lcd.print("Last line = ");    
lcd.print(line2);    

    dataFile.close();

I think it is more a hack, than a solution. So from now on you have to write two last lines.

If you are happy with it...

Well, my skills on Arduino are limited now, I cold get back to that code later…
It’s not clear to me why TWO lines?
The last line is always zero
So I have to pick up the previous one, which !=0.
As I can see, the code is working.

Thank you
Dmitry

You mean, I have to write to the SD file twice?
No. The writing procedure remains the same and the rest of the code reads the last value perfectly.. as I can see it.
Thank you once again!

If the last value has to be a 0 because you need it to find the second last,
writing a new second last needs another 0, don't you think so?

You were not able make the positioning work on read, so I doubt you will use it on write.

Example:
....
'5545,'
'0,'

  • new value (5654) via appending
    ....
    '5545,'
    '0,'
    '5644,'
    '0,'

wasting a lot of space (about same as used).

I use the previous code for writing, no nulls added.
Writing code makes these numbers on Sdcard:

5742,
5743,
5744,

I suppose that command

String line_str = dataFile.readStringUntil(',');

always returns "0" at the end. I read about this command and the manual says, that it returns a value when bumps into termination symbol (comma in my case) AND stops by timeout. This timeout is 1 sec by default. I supposed the last "0", which I always got in the end, is that timeout exit (sorry my clumsy explanation). To make sure, I changed the default timeout to 10000msec and saw the "0" appears in Comport monitor after that time.

So the monitor showed me:

5739,5740,5741,5742,5743,5744, (after timeout) 0

That's why I decided to take not the last value of what the function returns, but the pre-last.

Maybe my solution is clumsy (you've said it is hardly a solution), but I can't where the hack is.
As I mentioned, my skills in programming are limited.

As I can predict, to use this Sdfat lib, I should re-write all the code regarding reading/writing to/from SD card, because it conflicts with the standard SD lib.

Thank you for your help,
I can provide the whole sketch if you're still interesting in.
Anyway, I have made a fail-safe logger, which saves counter counts on SD and reads them back if there is a shutdown or reboot of Arduino.

As I can predict, to use this Sdfat lib, I should re-write all the code regarding reading/writing to/from SD card, because it conflicts with the standard SD lib.

The standard SD library is just a wrapper for a very old version of SdFat. You can use SdFat without rewriting your program but you won’t get new SdFat features.

Just replace

#include <SD.h"

With:

#include <SdFat.h>
SdFat SD;

SdFat has a number of examples for reading CSV files.

ReadCsvArray

ReadCsvFields

readCSV

You can also use readStringUntil() but it returns less information than readField

/*
 * Read a file one field at a time.
 *
 * file - File to read.
 *
 * str - Character array for the field.
 *
 * size - Size of str array.
 *
 * delim - String containing field delimiters.
 *
 * return - length of field including terminating delimiter.
 *
 * Note, the last character of str will not be a delimiter if
 * a read error occurs, the field is too long, or the file
 * does not end with a delimiter.  Consider this an error
 * if not at end-of-file.
 *
 */
size_t readField(File* file, char* str, size_t size, const char* delim);