0

I am trying to store some variables in a text file which is saved in a SD card, using the SD library. Every time my program runs, it load the values of those variables from the file. After a few minutes, my program will attempt to change the value of some variables (not all).

This is what I would in a C program. I would locate the position (using position()) where the values to be edited is present, and then using the seek() function I would write at the given position thus overwriting the file.

Each variable is stored in a separate row. But for some reason the program only writes at the end of the file, even if I have moved the file pointer elsewhere. How can I do the above task?

A simple example of the code is as follows:

#include <SD.h> //Load SD library

int chipSelect = 53;
File file;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(chipSelect, OUTPUT); // chip select pin must be set to OUTPUT mode

  Serial.print("Welcome!");
  Serial.println();

  bool initialization_state = SD.begin(chipSelect);
  delay(400); // SD card needs sometime to intialize

  if (!initialization_state) { // Initialize SD card
    Serial.println("Could not initialize SD card."); // if return value is false, something went wrong
  } else {  // if return value is true
    Serial.println("SD card initialized");
  }

  SD.remove("misc.txt");
  file = SD.open("misc.txt",FILE_WRITE);
  file.print("Once you know the central idea and a rough plan for your paragraphs, you need to arrange them in a certain manner to get your story across."); 
  file.println();
  file.print("Following are some possible ways of organizing your paragraphs."); 
  file.println();
  file.print("Narration: Tell a story. Go chronologically, from start to finish. Description: Provide specific details about what something looks, smells, tastes, sounds, or feels like.");
  file.println();
  file.print("Organize spatially, in order of appearance, or by topic. Process: Explain how something works, step by step. Perhaps follow a sequence—first, second, third.");
  file.close();
  read_file();
  Serial.print("Read?");
  Serial.println();

  update_file();
  read_file();
}

void loop() {
  // put your main code here, to run repeatedly:
}

void read_file() {
  Serial.println("--- Reading file ---");
  file = SD.open("misc.txt", FILE_READ);

  char character;
  while( (character = file.read()) != -1) {
    Serial.print(character);
  }
  Serial.println();
  file.close();
}

void update_file() {
  file = SD.open("misc.txt", FILE_READ);
  char character;
  while( (character = file.read()) != '\n') {}
  byte pos = file.position();
  file.close();

  file = SD.open("misc.txt", FILE_WRITE);
  file.seek(pos);
  file.print(" Love, love, love.");
  file.close();
} 

In this program I am attempting to overwrite the second line. The while loop breaks at the first newline character. I store the location of the first character in the second line in a variable pos. Then I open the file object for writing, I seek the position where I want to write (using file.seek(pos) ) and then I print into the file. But when I read the file, the text "Love, love, love." is written at the end.

I am using the linux Arduino IDE 1.8.9.

  • Personally I would read the file line by line, writing each line to a temporary file. You then change the lines that need changing on the fly. Afterwards you delete the old file and rename the temporary file to the old name. That way you can more easily handle changes in the length of data. – Majenko Aug 28 at 22:40
  • @Majenko Ok. But I was wondering if my approach could be performed on an arduino? Does the SD library not support it? – Mohammed Arshaan Aug 28 at 22:42
  • No reason why it shouldn't. However: how do you know that you are not seeking to the end of the file? – Majenko Aug 28 at 22:46
  • Because once I had located and stored pos. I closed the file object. Then opened another file object in FILE_READ, used file.seek(pos) to go to the location and printed the remaining file on the serial monitor. It had worked. – Mohammed Arshaan Aug 28 at 22:51
1

The problem is that you are opening the file with FILE_WRITE. That is a combined macro that is made up of:

#define FILE_WRITE (O_READ | O_WRITE | O_CREAT | O_APPEND)

The key one there is O_APPEND. In the source code (SdFile.cpp) t says:

O_APPEND - If set, the file offset shall be set to the end of the file prior to each write.

So the seek does nothing if O_APPEND is set, since it is overridden.

So instead you need to open the file without O_APPEND. In fact you don't need to close and open the file at all, since if opened correctly you can hop around at will reading and writing. The flag O_RDWR is a combination of O_READ and O_WRITE.

For example:

void update_file() {
  file = SD.open("misc.txt", O_RDWR);
  char character;
  while( (character = file.read()) != '\n') {}
  file.print(" Love, love, love.");
  file.close();
} 

The O_CREAT flag that is part of FILE_WRITE will create a new file if you try and open one that doesn't exist. By omitting that SD.open will fail if the file you are trying to modify doesn't exist.

  • Isn't file.seek(file.position()); a no-op? – Edgar Bonet Aug 29 at 7:14
  • @EdgarBonet Probably, yes. – Majenko Aug 29 at 9:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.