Einzelne Zeile in Binär-Datei ändern

Sorry, dachte zuerst nicht, dass das entscheidend ist. Sonst hätte ichs früher erwähnt.

hier ist ein Beispiel mit littleFS, es sollte nicht schwer sein, sich an die SD-Bibliothek anzupassen

der Code

  • erstellt eine Binärdatei "/10-2021.log" und füllt sie mit zufälligen Datensätzen (zwischen 3 bis 6 Datensätze pro Tag, für die ersten 10 Tage des Monats). [fillUpFile(testFileName)]
  • Ausgabe auf dem Seriellen Monitor [printFile(testFileName)]
  • die Aufzeichnungen von Tag 3 für ungültig erklären [invalidateDay(3, testFileName)]
  • Ausgabe auf dem Seriellen Monitor [printFile(testFileName)]

Die Verwendung einer Struktur trägt dazu bei, dass jeder Datensatz dieselbe Größe hat, sodass es einfach ist, einen bestimmten Datensatz in der Datei zu lesen/zu schreiben.

#include <LittleFS.h>

struct __attribute ((packed)) tRecord {
  bool      valid;
  uint8_t   dayOfMonth;
  uint8_t   humidity;
  int16_t   temperature;
};

const char * testFileName = "/10-2021.log";

void printFile(const char* filename) {
  tRecord aRecord;
  File dataFile = LittleFS.open(filename, "r");  // Open text file for reading
  Serial.println("-------------");
  while (dataFile.readBytes((char*) &aRecord, sizeof aRecord) != 0) {
    Serial.print("Valid: "); Serial.write(aRecord.valid ? 'Y' : 'N');
    Serial.print("\tDay: "); Serial.print(aRecord.dayOfMonth);
    Serial.print("\tH: "); Serial.print(aRecord.humidity);
    Serial.print("\tT°: "); Serial.println(aRecord.temperature);
  }
  Serial.println("-------------");
  dataFile.close();
}

void fillUpFile(const char* filename) {
  tRecord aRecord;
  aRecord.valid = true;

  File dataFile = LittleFS.open(filename, "w");  // Truncate file to zero length or create text file for writing
  for (byte day = 1; day <  11; day++) {
    aRecord.dayOfMonth = day;
    byte nbRecord = random (3, 7);
    for (byte record = 0; record < nbRecord; record++) {
      aRecord.humidity = random(0, 101);
      aRecord.temperature = random(-20, 50);
      dataFile.write((char*) &aRecord, sizeof aRecord);
    }
  }
  dataFile.close();
}

void invalidateDay(byte dayToInvalidate, const char* filename) {
  tRecord aRecord;
  File dataFile = LittleFS.open(filename, "r+");  // Open for reading and writing
  while (dataFile.readBytes((char*) &aRecord, sizeof aRecord) != 0) {
    if (aRecord.dayOfMonth == dayToInvalidate) {
      aRecord.valid = false;
      dataFile.seek(dataFile.position() - sizeof aRecord);
      dataFile.write((char*) &aRecord, sizeof aRecord);
    }
  }
  dataFile.close();
}

void setup() {
  while (!Serial);
  Serial.begin(74880); Serial.println();

  LittleFS.begin();
  LittleFS.format();
  fillUpFile(testFileName);
  printFile(testFileName);
  invalidateDay(3, testFileName);
  printFile(testFileName);
  LittleFS.end();
}

void loop() {}

Das klingt, als ob das perfekt passen könnte, danke schon mal dafür.
Teste ich aus und werde berichten.

Viele Grüße und schönen Restsonntag...der Montag wartet ja leider schon wieder ... aaargh!

Ich bin im Ruhestand, es ist jeden Tag Sonntag :slight_smile:

1 Like

Der Satz geht runter wie Öl, aber ich hab da leider noch mindestens zwei Dekaden vor mir...;-(

Das könnte 20 Jahre lang Spaß machen ... es liegt in Ihren Händen...

Da hast du natürlich recht... bis jetzt kann ich mich nicht wirklich beklagen, es gibt in der Tat schlimmere Leben, als das, was ich führe.

Hi,

jetzt hab ich doch noch mal ne Frage zu dem Beispiel:

an der Stelle wird ja die Datei im Modus r+ aufgerufen.
Das entspricht ja einem Lese + Schreib mit Beginn am ANFANG der Datei.

Daher kann man - sobald man die zu ändernde Position mit seek gefunden hat auch direkt schreiben also

Aber bei mir befindet sich die Datei ja auf der SD-Karte.
Und da gibts doch nur FILE_READ (Lesen, Start am Anfang der Datei) und FILE_WRITE (Schreiben, Start am ENDE der Datei)...?
Lässt sich mein Vorhaben dann mit der SD-Library gar nicht umsetzen?

Beste Grüße
Daniel

Teste es mit FILE_WRITE,

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

klingt so als müsstest du u.U. nur die Position korrigieren,
die steht nach dem Öffnen auf dem Ende der Datei.

Hi,

aber im ersten Schritt muss ich doch die Datei erstmal von Beginn an Zeile für Zeile durchlaufen, um die zu ändernde Stelle zu finden. Und wenn ich die Datei im Modus FILE_WRITE öffne, bin ich doch am Ende der Datei.

Oder meinst du so auf die Art (noch ungetestet, nur zusammenvermutet...):

Oder bin ich da voll auf dem Holzweg?

Da würde ich eine andere Strategie verfolgen.

Dem kann ich immer noch nichts hinzufügen, insofern verstehe ich deine Frage nicht.

Deine Vermutung ist ein Zitat? Verwirrend.

Wenn die Position nach dem Öffnen am Ende ist, führen Sie einfach einen dataFile.seek(0); aus, um zum Anfang zu gelangen

Ich würde empfehlen, SDFat zu verwenden

2 Likes

Das war mir zu viel Einlöffeln, ein wenig Mitdenken und Lernen hatte ich vom OP erwartet.

Ja sorry :see_no_evil:

Bei mir ist noch Lernpotential in alle Richtungen und manchmal ist so ein Schupser wie von @J-M-L leider noch nötig. Beim Fußball steht man manchmal ja auch vor dem leeren Tor und schießt dann drüber :wink:

Ich versuch mich zu bessern.
Danke euch beiden.

LG

Geht es denn jetzt?

Kann ich jetzt leider erst final heute Abend testen ;-(
Bin grad schon wieder unterwegs...
Aber ich werde berichten.

echt jetzt? warum tut man denn sowas beim Fussball?

Also, habs getestet.

Das hier...

...funktioniert wunderbar :wink:

Danke euch allen nochmal, wieder was dazugelernt.
Schönen Abend zusammen!

Dann nicht vergessen die entsprechenden Klicks zu machen.:wink:

1 Like

Hast Recht, sorry.
Obwohl ich selber die Lösung ja nicht gefunden hab, hab ich trotzdem mal meinen letzten Post als "Solution" markiert, weil da die Lösung letztendlich ja drin steht. Ich hoff das ist korrekt so.

LG