Binärdaten sauber in Logdatei schreiben

Gast #5001804
Lesenswert?

Hallo zusammen,

ich habe eine ganze Menge Daten, welche ich (mit einem STM32) auf eine 
SD-Karte logge. Es ist eine Mischung aus 32Bit, 16Bit und 1Bit Daten. 
Aktuell logge ich alle Daten als lesbare Zeichen. Da die Logfiles 
dadurch recht groß werden, wäre es sinnvoller die Daten direkt binär zu 
schreiben (spart Speicherplatz und das Ausgeben/Einlesen der Dateien 
wird schneller).
Mein Problem: Wie trenne ich die einzelnen Datensätze voneinander? Wenn 
ich davon ausginge, dass es niemals einen Schreibfehler geben kann, dann 
könnte ich natürlich von der bekannten Datensatzgröße ausgehen. Aber 
wenn ich das nicht garantieren kann, dann muss ich irgendein (oder 
mehrere) Trennzeichen haben, welches aber niemals in den Daten selber 
vorkommen kann.

Gibt es hierfür eine sinnvolle Lösung, ausser die Daten daraufhin zu 
überprüfen, dass nicht zufällig das gewählte Trennzeichen darin 
vorkommt?

Danke und Gruß, Heiko
Gast #5002029
Lesenswert?

Heiko schrieb:
> Da die Logfiles
> dadurch recht groß werden, wäre es sinnvoller die Daten direkt binär zu
> schreiben (spart Speicherplatz und das Ausgeben/Einlesen der Dateien
> wird schneller).
Ist das derzeit oder auf absehbare Zeit tatsächlich ein Problem für 
deine Anwendung? Nichts ist ätzender, als Log-/Konfigurationsdateien, 
die nur mit Spezialwerkzeug zu lesen sind...

Heiko schrieb:
> Gibt es hierfür eine sinnvolle Lösung, ausser die Daten daraufhin zu
> überprüfen, dass nicht zufällig das gewählte Trennzeichen darin
> vorkommt?
Jein. Sich Gedanken über das Format der Datensätze machen...
Geh mal anders ran an das Problem: Stell dir vor, es wäre keine 
Logdatei, sondern eine serielle Schnittstelle. Da würdest du dir 
sicherlich auch irgendein Datensatzformat ("Protokoll") ausdenken, bei 
dem du jederzeit den Anfang eines Satzes erkennst. Vermutlich würdest du 
noch eine Prüfsumme dranhängen.

Du musst dir halt einen Satztrenner aussuchen und diesen maskieren, 
falls er in den Nutzdaten vorkommt.
Gast #5002031
Lesenswert?

Da Du leider nicht geschrieben hast, in welcher Reihenfolge die Daten 
anfallen, kann ich Dir nur schreiben, wie ich das üblicher Weise mache.

Ich definiere meine Logdaten als struct (in C) und schreibe die Daten in 
dieser Größe binär sizeof(struct ....) auf die Platte.
Dadurch ist, solange die struct statisch ist, gewährleistet, dass immer 
die Satzgröße gleich ist.
Damit braucht man sich keine Satztrenner einfallen lassen und hat auch 
sonst
weniger Aufwand.
Lesen geht dann ebenso über die feste Satzlänge.
Wichtig dabei ist, dass man für beide Programme (Schreiben und Lesen) 
identische Compileroptionen setzt. Sonst geht das schief.
Persönliche Seite #5002034
Lesenswert?

So ganz klar ist mir die Datenstruktur nicht, d.h. ob die verschieden 
breiten Wörter zusammengehören oder unabhängig voneinander geschrieben 
werden. Aber es gab in der alten Zeit sog. fixed length records. Ein 
Marker am Anfang bestimmt den Typ des Datensatzes und von da an ist die 
Wortbreite klar, bspw. könntest du die ASCII-Zeichen 1, 6 und 3 
verwenden, gefolgt von jeweils dem 1-, 16- bzw. 32-bit-Wort.

Wenn hingegen immer die drei Datentypen zusammengehören, wird es nicht 
besser als 7 Byte-Blöcken, da ich für das 1-bit-Wort auch ein Byte 
verwenden würde. So geht es immer in 7er Schritten voran. Wenn 
Speicherplatz keine Rolle spielt, würd' ich auf 8bit aufrunden und bspw. 
immer einen Zeilenumbruch oder etwas ähnlich praktisches (NUL…) als 
Trenner einsetzen.
#5002118
Lesenswert?

Heiko schrieb:
> Hallo zusammen,
>
> ich habe eine ganze Menge Daten, welche ich (mit einem STM32) auf eine
> SD-Karte logge. Es ist eine Mischung aus 32Bit, 16Bit und 1Bit Daten.

Du solltest vielleicht erläutern, ob Deine Datenmischung immer im selben 
Verhältnis ensteht (was die Struct-Lösung oben begünstigen würde), oder 
in beliebigen Mischverhältnissen.
#5002204
Lesenswert?

Heiko schrieb:
> Mein Problem: Wie trenne ich die einzelnen Datensätze voneinander? Wenn
> ich davon ausginge, dass es niemals einen Schreibfehler geben kann, dann
> könnte ich natürlich von der bekannten Datensatzgröße ausgehen. Aber
> wenn ich das nicht garantieren kann, dann muss ich irgendein (oder
> mehrere) Trennzeichen haben, welches aber niemals in den Daten selber
> vorkommen kann.
>
> Gibt es hierfür eine sinnvolle Lösung, ausser die Daten daraufhin zu
> überprüfen, dass nicht zufällig das gewählte Trennzeichen darin
> vorkommt?

Die typische Lösung ist sowas wie 4 Byte "Synchronisationsmarker" im 
Datenstrom zu platzieren, die am Anfang eines Datensatzes stehen.

Die Wahrscheinlichkeit, dass in deinen Daten zufällig genau diese 4 Byte 
vorkommen ist verschwindend gering und selbst wenn es passiert, 
wiederholt die Synchronisationslogik die Suche nach dem Marker einfach 
für das nächste Paket noch einmal, sodass du nur ein Paket verlierst.

Also Idee ist, jedes Paket hat einen Marker am Anfang, und dann wird 
einfach kontinuierlich gelesen außer der Marker passt irgendwo nicht; in 
dem Fall ignorierst du einfach alle Daten bis zum nächsten Marker. Das 
ist sehr robust.
Gast #5002208
Lesenswert?

Sven B. schrieb:
> Die Wahrscheinlichkeit, dass in deinen Daten zufällig genau diese 4 Byte
> vorkommen ist verschwindend gering und selbst wenn es passiert,
> wiederholt die Synchronisationslogik die Suche nach dem Marker einfach
> für das nächste Paket noch einmal, sodass du nur ein Paket verlierst.

Als erste Lösung gut, aber unsauber. Darum wird das "zufällige 
Verlieren" mit Byte-Stuffing (hier Long-Stuffing) auf 0 reduziert. Sagen 
wir die Magic-Marker-Number soll 128, dann definieren wir noch eine 
weitere (129) und ersetzten jedes "natürliche" Auftreten von 128 oder 
129 durch zwei Zeichen: 129, (Zeichen + 10).

Der Start-Marker ist damit weiterhin 128, und wenn 129 auftaucht, wird 
die 129 gelöscht und das nächste Zeichen -10 genommen.
#5002248
Lesenswert?

Achim S. schrieb:
> Sven B. schrieb:
>> Die Wahrscheinlichkeit, dass in deinen Daten zufällig genau diese 4 Byte
>> vorkommen ist verschwindend gering und selbst wenn es passiert,
>> wiederholt die Synchronisationslogik die Suche nach dem Marker einfach
>> für das nächste Paket noch einmal, sodass du nur ein Paket verlierst.
>
> Als erste Lösung gut, aber unsauber. Darum wird das "zufällige
> Verlieren" mit Byte-Stuffing (hier Long-Stuffing) auf 0 reduziert. Sagen
> wir die Magic-Marker-Number soll 128, dann definieren wir noch eine
> weitere (129) und ersetzten jedes "natürliche" Auftreten von 128 oder
> 129 durch zwei Zeichen: 129, (Zeichen + 10).
>
> Der Start-Marker ist damit weiterhin 128, und wenn 129 auftaucht, wird
> die 129 gelöscht und das nächste Zeichen -10 genommen.

Hmja, ist nett, aber ist das wirklich nötig? Daten verlierst du eh nur 
dann wenn sowieso schon was fehlerhaft ist, und dann höchstens ein Paket 
mehr als beschädigt wurde ... mit einer typischerweise völlig 
verschwindenden Wahrscheinlichkeit bei 4 Byte Marker ...
#5002323
Lesenswert?

Heiko schrieb:
> dann muss ich irgendein (oder
> mehrere) Trennzeichen haben, welches aber niemals in den Daten selber
> vorkommen kann.

(1) Mit Endezeichen (bspw. irgendein Byte). Kommt das Endezeichen in den 
Daten vor, wird es dort doppelt geschrieben. Records werden als 
Bytesequenzen betrachtet und können unterschiedliche Länge haben.

(2) Bei ASCII benutzt du nur einen Teil des Zeichensatzes für die 
"Zahlen". Einen anderen Teil für Markierungen. Definierte dir deinen 
eigenen Zeichensatz, der dichtere Daten erlaubt (z.B. BCD, BASE64, 
etc.).

(3) Führe eine Checksum ein, die an das Ende des Records angehangen 
wird. (Damit sollte man schnell synchronisieren können.)

> ich habe eine ganze Menge Daten, welche ich (mit einem STM32) auf eine
> SD-Karte logge.

In einem Thread hier im Forum wurde kürzlich die (un)Eignung von SD 
Karten für zuverlässiges Speichern diskutiert.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren