Редактирование определенной позиции в файле, хранящемся на SD-карте

Я пытаюсь сохранить некоторые переменные в текстовом файле, который сохраняется на SD-карте, используя SD-библиотеку. Каждый раз, когда моя программа запускается, она загружает значения этих переменных из файла. Через несколько минут моя программа попытается изменить значение некоторых переменных (не всех).

Это то, что я сделал бы в программе на языке Си. Я бы нашел позицию (используя position()), в которой присутствуют редактируемые значения, а затем, используя функцию seek(), я бы записал в заданной позиции, перезаписав таким образом файл.

Каждая переменная хранится в отдельной строке. Но по какой-то причине программа записывает только в конец файла, даже если я переместил указатель на файл в другое место. Как я могу выполнить вышеуказанную задачу?

Простой пример кода выглядит следующим образом:

#include <SD.h> //Загрузить библиотеку SD

int chipSelect = 53;
File file;

void setup() {
  // поместите сюда свой установочный код, чтобы запустить его один раз:
  Serial.begin(9600);
  pinMode(chipSelect, OUTPUT); // pin выбора микросхемы должен быть установлен в режим ВЫВОДА

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

  bool initialization_state = SD.begin(chipSelect);
  delay(400); // SD-карте требуется некоторое время для инициализации

  if (!initialization_state) { // Инициализировать SD-карту
    Serial.println("Could not initialize SD card."); // если возвращаемое значение равно false, что-то пошло не так
  } else {  // если возвращаемое значение равно 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() {
  // поместите сюда свой основной код для повторного запуска:
}

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();
} 

В этой программе я пытаюсь перезаписать вторую строку. Цикл while прерывается при первом символе новой строки. Я сохраняю местоположение первого символа во второй строке в переменной pos. Затем я открываю объект file для записи, ищу позицию, в которой я хочу записать (используя file.seek(pos)), а затем печатаю в файл. Но когда я читаю файл, в конце написан текст "Люблю, люблю, люблю".

Я использую linux Arduino IDE 1.8.9.

, 👍1

Обсуждение

Лично я бы прочитал файл построчно, записывая каждую строку во временный файл. Затем вы меняете строки, которые нужно менять на лету. После этого вы удаляете старый файл и переименовываете временный файл на старое имя. Таким образом, вы сможете легче обрабатывать изменения в объеме данных., @Majenko

@Majenko Хорошо. Но мне было интересно, может ли мой подход быть выполнен на arduino? Разве библиотека SD не поддерживает его?, @Mohammed Arshaan

Нет причин, почему бы и нет. Однако: откуда вы знаете, что вы не ищете до конца файла?, @Majenko

Потому что когда-то я нашел и сохранил pos. Я закрыл файловый объект. Затем открыл другой файловый объект в FILE_READ, использовал file.seek (pos), чтобы перейти к местоположению, и распечатал оставшийся файл на последовательном мониторе. Это сработало., @Mohammed Arshaan


1 ответ


Лучший ответ:

3

Проблема в том, что вы открываете файл с помощью FILE_WRITE. Это комбинированный макрос, который состоит из:

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

Ключевым из них является O_APPEND. В исходном коде (SdFile.cpp) т говорит:

O_APPEND - Если задано, смещение файла должно быть установлено в конец файла перед каждой записью.

Таким образом, поиск ничего не делает, если установлен параметр O_APPEND, поскольку он переопределяется.

Поэтому вместо этого вам нужно открыть файл без O_APPEND. На самом деле вам вообще не нужно закрывать и открывать файл, так как при правильном открытии вы можете перемещаться по желанию, читая и записывая. Флаг O_RDWR представляет собой комбинацию O_READ и O_WRITE.

Например:

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

Флаг O_CREAT, который является частью FILE_WRITE, создаст новый файл, если вы попытаетесь открыть тот, который не существует. Если опустить это, SD.open завершится неудачей, если файл, который вы пытаетесь изменить, не существует.

,

Разве file.seek(file.position()); не является ошибкой?, @Edgar Bonet

@EdgarBonet Наверное, да., @Majenko