Einzelne Zeile in Binär-Datei ändern

Hi zusammen,

ich hab mal wieder eine Frage :wink:

Angenommen, ich habe eine binäre-Datei namens "10-2021.bin" habe, in der z.B. pro Tag eine Temperaturmessung gespeichert wurde. Da möchte ich einen bestimmten Wert (also Tag) löschen, z.B. den 10.10.2021. Wie würdet ihr das vom Prinzip her am "smartesten" umsetzen?

Klar, man könnte pro Tag eine einzelne Datei anlegen, aber wenn man eben alles in einer Datei hat - wie würde man sowas umsetzen?

Mein aktueller Ansatz:

if (SD.begin(15)) {
    int jahr=2021;
    char filename[12];
    for (uint8_t monat = 1; monat < 13; monat++) {
      sprintf(filename, "%02d-%d.bin", monat, jahr);
      File tmpFile = SD.open(filename, FILE_READ);
      while (tmpFile.available()) {
        tmpFile.read((uint8_t *)&summe, sizeof(summe));
        //Meine aktuelle Lösung wäre, dass - wenn z.B. der 10.10.2021 gelöscht werden soll 
        //parallel an dieser Stelle eine neue Datei "temp.bin" geschrieben wird und der Wert 
        //des 10.10. dann eben nicht in diese Datei übernommen wird.
        //Aber ist es evtl. direkt an dieser Stelle möglich, eine Zeile zu löschen ohne
       //eine neue Datei schreiben zu müssen?
      }
      tmpFile.close(); 
      // An dieser Stelle würde ich dann die ausgelesene Datei "10-2021.bin" löschen und die neue
     // temporär geschriebene Datei "tmp.bin" umbenennen in "10-2021.bin" 
    }
}

Aber ist das die klügste Lösung oder kann man das noch besser machen?
Hier fehlts mir wieder entweder an Grips oder an Erfahrung :wink:

Viele Grüße

Wenn sich die zu löschenden Datensätze am Ende der Datei befinden, können Sie die Datei einfach an der richtigen Stelle zuschneiden. Die Standardbibliothek enthält nicht die Funktion File.truncate(), was die übliche Methode ist, aber wenn Sie stattdessen die SdFat-Bibliothek verwenden, können Sie die Funktion truncate() verwenden

Wenn sie in der Mitte sind, gibt es keine Option. Sie müssen eine neue temporäre Datei mit den Datensätzen vor und nach den nicht gewünschten Datensätzen erstellen, dann die alte Datei löschen und die temporäre Datei umbenennen.

  1. Eine Binärdatei hat überhaupt keine Zeilen. Du meinst vermutlich sizeof(summe) Bytes.
  2. Eine Datei ist ein fortlaufender Stream. Da mittendrin etwas löschen geht nur, indem man sie umkopiert und dabei das zu löschende weglässt. So wie du im Kommentar vermutest.
  3. Ob eine Binärdatei noch Sinn macht, wenn ein Stück mittendrin fehlt, ist generell fraglich. Kann man an deinem Schnipsel nicht erkennen.
  4. Das Wesentliche fehlt : summe ist undefiniert.
  5. Bei kleinen Arduinos (atmega328) ist es problematisch, zwei Dateien gleichzeitig offen zu zu haben. (RAM - Bedarf !)
1 Like

Du kannst ein Bit (Byte) pro Datensatz vorsehen die angeben ob ein Datensatz gültig ist oder gelöscht ist.
Da ich noch nie mit Sd Karten am Arduino gearbeitet habe weiß ich nicht ob es möglich ist einzelne Bytes eines Files auf der Sd-Karte zu ändern.
Grüße Uwe

es ist möglich (und eine gute Idee).

das würde so oder so nicht funktionieren, denn das element filename[12] existiert nicht. es gibt nur Filename[0] - Filename [11], da bei arrays immer mit dem element 0 begonnen wird, Entweder müsstest du char filename[13] deklarieren, was aber platzverschwendung ist, oder in der der forschleife schreiben

Dies aber nur zum allgemeinen Umgang mit Arrays.

Ich verstehe nicht, was Sie sagen hier. Dies scheint mir in Ordnung. (monat ist kein Index im filename Array)

Änderungen in einer Datei sind einfacher und sinnvoller, wenn alle Datensätze gleich lang sind.
(weil man die Position eines Datensatzes berechnen kann, z.B. aus einer Tagesnummerierung)
So ein Datensatz kann natürlich auch eine gültig/ungültig Kennzeichnung haben.
Bei vielen Daten ist ein sequenzieller Zugriff oft zu langsam,
für einen Zeilenindex ist zu wenig Speicher da, gleiches für eine Indexdatei.

Ich habe eine binäre Indexdatei als Verknüpfung zu Positionen in einer anderen Datei verwendet. Auf einer UNO funktionierte es einwandfrei.

EDIT: das war auf einem MEGA

Ich denke auch, auf einem UNO wird's eng. :wink:

wird es aber hier:

Möchten Sie erklären, was das Problem ist? ? (2 + 1 + 4 + 4 = 11 chars plus nachgestelltes '\0' = 12)

Nein.
er baut einen char-Array mit 12 Elementen.
"01-2021.bin" macht \0 terminiert 12 Elemente.
passt.

Du hast einen Denkfehler. :wink: Ich kanns nur nicht erklären...

Hi,

den char array nutze ich nur, um bei jedem Durchgang der For-Schleife den Dateinamen der auszulesenden Datei zusammen zu bauen.
Das funktioniert auch wunderbar so.

Grüßle Daniel

Das ist ein interessanter Ansatz.
Du hast nicht zufällig ein Beispiel in der Hosentasche;-)
Ansonsten werd ich wohl eine parallele Datei schreiben.
Als Microcontroller nutze ich einen Wemos D1 Mini

Doch , das konntest Du. Ist zumindest mit Deiner Erklärung mir klargeworden. Mein Denkfehler war das ich die 12 auf die anzalh monate bezog, anstatt auf die Namenslänge +'/0' in filename[ ]

verwenden Sie eine echte SD-Karte oder ist die Log-Datei in SPIFFS?

Ich verwende eine SD Karte weil die Speicherzyklen auf dem SPIFFS ja begrenzt sind. By the way: du darfst mich gerne duzen. Sonst komm ich mir noch älter vor als ich eh schon bin

Wäre clever gewesen, das im Eingangspost zu erwähnen. :wink:

Ich werde es versuchen ... Ich bin ein "alter Mann", der vor langer Zeit Deutsch gelernt hat ... 'Sie' war damals der richtige Weg ...

1 Like