Overwriting values on SD card

This is quiet an old topic, but I have not been able to find an answer in other threads.

I am using the SD.lib for storing some sensor values on an SD card. Specifically, in this project I want to make several files each storing 72 values all of the same length.

So far, I have succeed in writing to the end of the file and reading specific positions by using position() and seek(). I have tried to use position() and write() to overwrite a specific line of the file, but the write() function will always write to the end of the file.

I have read that instead of using myFile = SD.open("test.txt", FILE_WRITE) it is possible to open the file in truncate mode, which should make overwriting possible. But, how do I do this?

What I want to do:
My file has the following content:

12341
12342
12343
12344

And I want to overwrite line 2 with 12345 so the file becomes:

12341
12345
12343
12344

I have read that instead of using myFile = SD.open("test.txt", FILE_WRITE) it is possible to open the file in truncate mode, which should make overwriting possible. But, how do I do this?

If you open a file, in truncate mode, that has data in it, that data will be deleted. I do not think that that is what you want to do.

I have tried to use position() and write() to overwrite a specific line of the file, but the write() function will always write to the end of the file.

If that statement IS true, there is something wrong with your code.

If you want help with your code, you must post your code, in code tags.

That's funny. That's the same thing I need to do. I haven't been able to figure out an easy or short way to do it. If you figure it out, please post it.

PaulS:
If you open a file, in truncate mode, that has data in it, that data will be deleted. I do not think that that is what you want to do.
If that statement IS true, there is something wrong with your code.

If you want help with your code, you must post your code, in code tags.

Okay, thank you. I was spending a lot of time on this and couldn't figure out, why it kept deleting the content of my file. So it turns out that I did open it in truncate mode, but that truncate mode is not what I want.

Now I opened it again using FILE_WRITE and was able to overwrite a line as i wanted. I will post an example later in case others have the same problem.

Thanks :slight_smile:

adwsystems:
That's funny. That's the same thing I need to do. I haven't been able to figure out an easy or short way to do it. If you figure it out, please post it.

So I start by the following:

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

File myFile;

void setup() {
 Serial.begin(9600);
 
 SD.begin(4);
 myFile = SD.open("test.txt", FILE_WRITE);

 //write to file   
 myFile.println("12341"); //writes line 1
 myFile.println("12342"); //writes line 2
 myFile.println("12343"); //writes line 3
 myFile.println("12344"); //writes line 4
 myFile.close();

 //read from file
 myFile = SD.open("test.txt");

 Serial.println(readLine()); //reads line 1
 Serial.println(readLine()); //reads line 2
 Serial.println(readLine()); //reads line 3
 Serial.println(readLine()); //reads line 4
 myFile.close();  
}

String readLine()
{
 String received = "";
 char ch;
 while (myFile.available())
 {
   ch = myFile.read();
   if (ch == '\n')
   {
     return String(received);
   }
   else
   {
     received += ch;
   }
 }
 return "";
}

void loop() {
 // nothing happens after setup
}

This creates a file with the desired content and outputs the content to the serial monitor:
12341
12342
12343
12344

To find the position of the begining of line 2, I run the following code:

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

File myFile;

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

 //read from file
 myFile = SD.open("test.txt");

 Serial.println(readLine()); //reads line 1
 Serial.println(myFile.position()); //prints the position for the beginning of line 2
 Serial.println(readLine()); //reads line 2
 Serial.println(readLine()); //reads line 3
 Serial.println(readLine()); //reads line 4
 myFile.close();
}

String readLine()
{
 String received = "";
 char ch;
 while (myFile.available())
 {
   ch = myFile.read();
   if (ch == '\n')
   {
     return String(received);
   }
   else
   {
     received += ch;
   }
 }
 return "";
}

void loop() {
 // nothing happens after setup
}

The output on the serial monitor is:
12341
7
12342
12343
12344

This output shows that line 2 starts at position 7.
Line 2 can be overwritten with:

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

File myFile;

void setup() {
 Serial.begin(9600);
 
 SD.begin(4);
 myFile = SD.open("test.txt", FILE_WRITE);

 //write to file
 myFile.seek(7); //goes to the beginning of line 2    
 myFile.println("12345");
 myFile.close();

 //read from file
 myFile = SD.open("test.txt");

 Serial.println(readLine()); //reads line 1
 Serial.println(readLine()); //reads line 2
 Serial.println(readLine()); //reads line 3
 Serial.println(readLine()); //reads line 4
 myFile.close();
}

String readLine()
{
 String received = "";
 char ch;
 while (myFile.available())
 {
   ch = myFile.read();
   if (ch == '\n')
   {
     return String(received);
   }
   else
   {
     received += ch;
   }
 }
 return "";
}

void loop() {
 // nothing happens after setup
}

So now its time to write the real program :slight_smile:

 String received = "";
 char ch;
 while (myFile.available())
 {
   ch = myFile.read();
   if (ch == '\n')
   {
     return String(received);

Why do you create a new String instance from the received String?

PaulS:

 String received = "";

char ch;
while (myFile.available())
{
  ch = myFile.read();
  if (ch == '\n')
  {
    return String(received);



Why do you create a new String instance from the received String?

It is some code, that I copied form Arduino SD Card Tutorial - educ8s.tv - Watch Learn Build. I think the point is, that it only reads characters until the line terminates and not everything that is stored in the file.

Or maybe I don't understand your question. I'm pretty new to programming.

It is some crap, that I copied form Arduino SD Card Tutorial - educ8s.tv - Watch Learn Build.

Oh, well.

PaulS:
Oh, well.

Ha ha :slight_smile: Can you enlighten me why it is crap? Is it because, he can save memory by reusing the other string?

Anyway, I am not going to use the code, since I want to read numbers and store them in an int. So I wrote this function (numbers stored on the SD card always consist of 5 characters):

int readNumber()
{
  int x = 0;
  int z = 10000;
  
  for (int i=0; i<5; i++){
    x = (myFile.read()-48)*z + x;
    z = z / 10; 
  }

  return x;
}

Please feel free to comment for improvements :slight_smile:

Is it because, he can save memory by reusing the other string?

Partly it is crap because there is no reason to make a copy of the String.

   return received;

Partly it is crap, because it uses Strings in the first place. With the limited memory on the Arduino, the String class, with all the dynamic memory allocation/freeing that it does, is just not a good fit.

    x = (myFile.read()-48)*z + x;

Where did the 48 come from? While I know the answer,

    x = (myFile.read() - '0')*z + x;

does not require that I know anything about the ASCII table.

Where did the 48 come from? While I know the answer,

x = (myFile.read() - '0')*z + x;

Ah, cool. Thanks for all the help