Forum: Mikrocontroller und Digitale Elektronik Elm chan Fat: Zeichen überschreiben


von Andreas B. (bitverdreher)


Lesenswert?

ich stehe momentan etwas auf den Schlauch. Es geht darum eine config 
datei unter Verwendung der Elm-chan FatFs lib von einer SD card 
einzulesen. Das funktioniert soweit auch gut.
Diese config Datei besteht aus mehreren Zeilen, wobei jede Zeile einen 
Eintrag bildet (soweit alles normal). Ich lese sie Zeile für Zeile ein 
und werte den entsprechenden Eintrag aus. So weit, so schön.

Jetzt möchte ich aber in dieser config Datei nach dem lesen bestimmte 
Zeichen überschreiben (damit ändert sich die Dateigröße ja nicht) um 
bestimmte Einträge nach dem Lesen als ungültig zu kennzeichnen.
Wie stelle ich das am besten an?
Datei erst zum lesen öffnen und später beschreiben?
Wie bekomme ich den Pointer auf den aktuellen Eintrag?
Kann man, während die Datei als R/W offen ist, gleichzeitig lesen und 
schreiben?
Oder muß ich letztendlich doch die komplette Datei neu schreiben? Das 
würde halt jede Menge Buffer benötigen. uC ist ein LPC11U35. Das Ram 
könnte dazu reichen, aber gefallen tut mir das nicht.
Irgendwie ist mir die komplette Vorgehensweise dabei nicht klar. Kann 
mir da mal jemand auf die Sprünge helfen?

von Gerhard O. (gerhard_)


Lesenswert?

Wie wäre es wenn Du einfach die Config Datei zeilenweise einliest, 
bearbeitest und dann in derselben Reihenfolge in eine neue Datei 
schreibst. So eine Vorgehensweise würde ein Minimum an SRAM 
beanspruchen. Die zu lesende Datei kann man nachher löschen.
Wenn die Datei unter keinen Umständen beschädigt werden darf, vielleicht 
vorher noch eine Kopie anfertigen.

von Andreas B. (bitverdreher)


Lesenswert?

Hmm, die Grundidee ist gut. Dann müßte man die Datei unter einen anderen 
Namen speichern, das Original löschen und dann umbenennen. Das wäre halt 
relativ viel Geschreibe auf der Karte, aber wenn es anders nicht geht...

Ein Punkt noch: Die Reihenfolge der Zeilen wäre egal. Falls noch Ideen 
kommen. ;-)

von Falk B. (falk)


Lesenswert?

Andreas B. schrieb:

> Jetzt möchte ich aber in dieser config Datei nach dem lesen bestimmte
> Zeichen überschreiben (damit ändert sich die Dateigröße ja nicht) um
> bestimmte Einträge nach dem Lesen als ungültig zu kennzeichnen.
> Wie stelle ich das am besten an?
> Datei erst zum lesen öffnen und später beschreiben?
> Wie bekomme ich den Pointer auf den aktuellen Eintrag?

f_seek().

> Kann man, während die Datei als R/W offen ist, gleichzeitig lesen und
> schreiben?

Kann sein.

von Harald (Gast)


Lesenswert?

Kannst Du nicht eine zweite Datei mit den gewünschten Änderungen Zeile 
für Zeile anfertigen, ohne die Originaldatei zu "beschädigen"? Bei 
Vorhandensein dieser zweiten Datei (z.B. mit anderer Endung) kann das 
System daraus ja die notwendigen Rückschlüsse ziehen und damit 
weitermachen bzw. wenn diese beschädigt ist aus der Orignialdatei eine 
Neue erzeugen.

von Rolf M. (rmagnus)


Lesenswert?

Andreas B. schrieb:
> Hmm, die Grundidee ist gut. Dann müßte man die Datei unter einen anderen
> Namen speichern, das Original löschen und dann umbenennen.

Ich weiß nicht, ob das bei dieser fat-Lib so geht, aber das übliche 
Pattern ist, die neue Datei als versteckte Datei im gleichen Verzeichnis 
anzulegen und nach dem Schreiben auf den Namen des Originals 
umzubenennen, aber ohne die vorher zu löschen. Das hat nämlich den 
Vorteil, dass das dann aus Dateisystemsicht eine atomare Operation ist. 
Es kann nicht vorkommen, dass zwischen dem löschen und dem umbenennen 
irgendwas passiert, das dazu führt, dass du ohne gültige 
Konfigurationsdatei da stehst.

Falk B. schrieb:
>> Kann man, während die Datei als R/W offen ist, gleichzeitig lesen und
>> schreiben?
>
> Kann sein.

Würde ich eigentlich erwarten. Wozu sonst sollte es einen Modus "R/W" 
geben?

von René H. (mumpel)


Lesenswert?

Andreas B. schrieb:
> Das wäre halt relativ viel Geschreibe auf der Karte,

Du schreibst zuerst in eine Variable, und erst wenn Du fertig bist 
schreibst Du in die Datei.

von Andreas B. (bitverdreher)


Lesenswert?

Harald schrieb:
> Kannst Du nicht eine zweite Datei mit den gewünschten Änderungen Zeile
> für Zeile anfertigen, ohne die Originaldatei zu "beschädigen"?

Das war ja die Idee von Gerhard.
Aber es stimmt schon: Ich werde die alte Datei nicht löschen sondern 
umbenennen und dann die neu erzeugte auf den Original Namen umbenennen. 
Dann hätte man noch das Original falls was schief laufen sollte.

Rolf M. schrieb:
> Es kann nicht vorkommen, dass zwischen dem löschen und dem umbenennen
> irgendwas passiert, das dazu führt, dass du ohne gültige
> Konfigurationsdatei da stehst.
Wenn ich das so mache wie eben beschrieben (nicht löschen), dann 
passiert das nicht.

von Dosenfutter (Gast)


Lesenswert?

Rolf M. schrieb:
> Würde ich eigentlich erwarten. Wozu sonst sollte es einen Modus "R/W"
> geben?

Laut ChaNs Webseite kann die Library das. Wie das in der Praxis aussieht 
muss man mal schauen. f_seek() wurde ja schon genannt.

So generell habe ich ein paar Bauchschmerzen wenn mit zeilenorientierten 
(Text?) Dateien gearbeitet wird, es aber feste Positionen in der Datei 
gibt. Ich würde statt dessen eine Binärdatei mit TLV-Aufbau verwenden 
https://de.wikipedia.org/wiki/Type-Length-Value und noch ein Valid-Flag 
(Bit oder Byte) einführen, das sagt ob der Eintrag gültig ist. Das 
Valid-Flag lässt sich kontrollierter setzen oder löschen als in einer 
Textdatei Daten überschreiben oder ausnullen.

von Andreas B. (bitverdreher)


Lesenswert?

Dosenfutter schrieb:
> So generell habe ich ein paar Bauchschmerzen wenn mit zeilenorientierten
> (Text?) Dateien gearbeitet wird, es aber feste Positionen in der Datei
> gibt.
Naja, es ist eine config Datei, die vom Anwender editiert werden soll.
Das genannte f_seek positioniert lediglich auf eine Bytenummer, die erst 
mal gefunden werden muß. Solange das innerhalb des gleichen Blocks liegt 
ist es ja noch einfach. Dann wird es aber kompliziert.

Ansonsten: Danke für die Tips. Ich habe es jetzt so umgesetzt:
Datei wird normal gelesen. Falls ein diesbezüglicher Eintrag auftaucht 
wird ein Flag gesetzt.
Am Schluss wird das Flag abgefragt und im gesetzten Fall die Datei 
nochmals Satz für Satz durchgegangen und die entsprechenden Einträge auf 
ungültig gesetzt. Das wird dann in eine neue Datei geschrieben.
Abschließend werden beide Dateien umbenannt.

Damit das Ganze nicht allzu geheimnisvoll aussieht: Bei den besagten 
Datensätzen handelt es sich um die Uhrzeit oder Zeitkorrektur für die 
RTC. Das soll halt nur einmal gesetzt werden, falls das Programm 2x 
gestartet wird. Dieser Eintrag sollte auch nur vorkommen, falls die RTC 
mal nicht (Batterie leer) oder falsch geht.

von the maverfehlung (Gast)


Lesenswert?

Andreas B. schrieb:
> Damit das Ganze nicht allzu geheimnisvoll aussieht:

Aber was hat das Ganze denn mit dem Thema Elm Chan FAT zu tun?
Es ist doch nur ein Problem ob ich eine Datei zeilenweise
oder zeichenweise behandle, und das sollte unabhängig vom
verwendeten Dateisystem sein, sofern es einigermassen
"vernünftig" implementiert ist, was man von dem beliebten
Elm Chan FAT nun mal annehmen darf. Sonst hätte man davon
schon längst was gehört.

von Andreas B. (bitverdreher)


Lesenswert?

the maverfehlung schrieb:
> Aber was hat das Ganze denn mit dem Thema Elm Chan FAT zu tun?

Jetzt nicht mehr. Ursprünglich wollte ich die Datei sowohl mit dem Read 
als auch mit dem Write Flag öffnen und dieses eine Zeichen 
überschreiben. Da kamen aber keine konkreten Tips dazu. So oft scheint 
diese Anforderung wohl doch nicht vorzukommen.
Nochmal: Es ging um das Überschreiben eines chars in einer schon 
vorhandenen Textdatei.

von John (Gast)


Lesenswert?

Andreas B. schrieb:
 .
> Jetzt möchte ich aber in dieser config Datei nach dem lesen bestimmte
> Zeichen überschreiben (damit ändert sich die Dateigröße ja nicht) um

f_seek() wurde ja schon genannt, du suchst dann in deiner config datei 
an welcher stelle das Zeichen steht und überschreibst das dann.

von c-hater (Gast)


Lesenswert?

Andreas B. schrieb:

> Datei erst zum lesen öffnen und später beschreiben?

Wenn du immer überschreiben willst: Natürlich nicht, dann kannst du sie 
auch gleich RW öffnen.

> Wie bekomme ich den Pointer auf den aktuellen Eintrag?

Durch rechnen und seeken. Fies bei zeilenweiser Verarbeitung: 
Zeilenumbrüche haben keine definierte Länge. Können typisch ein oder 
zwei Bytes lang sein. Das erschwert das Rechnen ein wenig, wenn die 
eigenen Routinen nur mit den Zeileninhalten werkeln und das Handling der 
Zeilen irgendeinem anderen Software-Teil überlassen wird. Typisches 
Anfängerproblem...

> Kann man, während die Datei als R/W offen ist, gleichzeitig lesen und
> schreiben?

Ja, klar. Das ist der Sinn dieses Modus.

von Falk B. (falk)


Lesenswert?

c-hater schrieb:
>> Wie bekomme ich den Pointer auf den aktuellen Eintrag?
>
> Durch rechnen und seeken.

Soso, seeken. Klingt eher sick . . .

von Andreas B. (bitverdreher)


Lesenswert?

c-hater schrieb:
> Durch rechnen und seeken.
Das ist schon klar und auch nicht das Problem. Die Frage wäre gewesen: 
Funktioniert das bei dieser lib auch über alle Blöcke der Datei? Die 
können  ja sonst wo liegen.
f_lseek (nicht fseek) benötigt eine Position. Ist das jetzt die gleiche 
wie diejenige, die ich mit durchzählen der gelesenenen chars finde oder 
haut mir da die Blockverwaltung dazwischen?
Was ich dazu letztendlich brauche ist ein Pointer, der konkret darauf 
zeigt, wo sich der Lesezeiger gerade befindet. Und das muß dann auch der 
gleiche sein, den ich bei f_lseek anwende.

> Das erschwert das Rechnen ein wenig, wenn die
> eigenen Routinen nur mit den Zeileninhalten werkeln und das Handling der
> Zeilen irgendeinem anderen Software-Teil überlassen wird. Typisches
> Anfängerproblem...
Das hat mit Anfänger herzlich wenig zu tun. Die config Date wird von 
irgend jemanden auf die Karte geschrieben. Ob das jetzt mit CR oder 
CR/LF gemacht wird, ist im Prinzip ja auch egal, wenn der entsprechende 
String gesucht wird. Man kann sich ja vor dem Lesen des Satzes den 
Anfang merken und muß nicht rückwärts suchen.

>> Kann man, während die Datei als R/W offen ist, gleichzeitig lesen und
>> schreiben?
>
> Ja, klar. Das ist der Sinn dieses Modus.
Das ist nicht klar. Es gibt bei dieser lib ein Flag zu schreiben und 
eins zum lesen beim Datei öffnen. So gesehen ist das kein expliziter 
Modus. Kann also sein oder auch nicht.

Ich wollte eigentlich auch keine Allgemeinplätze als Antwort haben, 
sondern konkret was und wie das bei dieser lib funktioniert. Sorry, aber 
bis jetzt hatte ich von niemanden den Eindruck, daß er die Elm-chan lib 
konkret kennt (und damit meinte ich nicht: Irgendwann mal benutzt 
haben).

von Falk B. (falk)


Lesenswert?

Andreas B. schrieb:
> c-hater schrieb:
>> Durch rechnen und seeken.
> Das ist schon klar und auch nicht das Problem. Die Frage wäre gewesen:
> Funktioniert das bei dieser lib auch über alle Blöcke der Datei? Die
> können  ja sonst wo liegen.

Aber sicher! Das ist doch kein Bastelmurks sondern feinste Software vom 
Meister Chan persönlich!

> f_lseek (nicht fseek) benötigt eine Position. Ist das jetzt die gleiche
> wie diejenige, die ich mit durchzählen der gelesenenen chars finde

Sicher, das ist die Byteposition in der Datei!

> oder
> haut mir da die Blockverwaltung dazwischen?

NEIN!

> Das ist nicht klar. Es gibt bei dieser lib ein Flag zu schreiben und
> eins zum lesen beim Datei öffnen. So gesehen ist das kein expliziter
> Modus. Kann also sein oder auch nicht.

Es ist so.

> Ich wollte eigentlich auch keine Allgemeinplätze als Antwort haben,
> sondern konkret was und wie das bei dieser lib funktioniert. Sorry, aber
> bis jetzt hatte ich von niemanden den Eindruck, daß er die Elm-chan lib
> konkret kennt (und damit meinte ich nicht: Irgendwann mal benutzt
> haben).

Ich hab sie benutzt, wenn gleich das schon ne Weile (tm) her ist und ich 
keinen RW Modus benutzt habe.

RTFM!

http://elm-chan.org/fsw/ff/doc/open.html
1
FA_READ   Specifies read access to the file. Data can be read from the file.
2
FA_WRITE  Specifies write access to the file. Data can be written to the file. Combine with FA_READ for read-write access.

von Andreas B. (bitverdreher)


Lesenswert?

Falk B. schrieb:
>> Kann man, während die Datei als R/W offen ist, gleichzeitig lesen und
>> schreiben?
>
> Kann sein.

Falk B. schrieb:
>> Das ist nicht klar. Es gibt bei dieser lib ein Flag zu schreiben und
>> eins zum lesen beim Datei öffnen. So gesehen ist das kein expliziter
>> Modus. Kann also sein oder auch nicht.
>
> Es ist so.

Aha.

Falk B. schrieb:
> Ich hab sie benutzt, wenn gleich das schon ne Weile (tm) her ist und ich
> keinen RW Modus benutzt habe.
Eben. ;-) Das war ja meine Hoffnung, daß jemand genau das schon einmal 
mit dieser lib gemacht hat.
Aber ich glaube Dir jetzt mal, daß das so funktioniert und werde es bei 
Gelegenheit mal testen.

von Andreas B. (bitverdreher)


Lesenswert?

Also, ich habe mich jetzt mal dran gemacht. Vorneweg: Es funktioniert 
prima und auch recht simpel (meine Hochachtung vor dem großen Meister 
Elm chan):
- Datei mit flags FA_READ | FA_WRITE öffnen.
- Vor jedem f_gets aus dem File Object den fptr auslesen und nach START 
speichern (der zeigt genau auf das n. Zeichen der Datei).
- Satz mit f_gets lesen
- fptr sichern (zeigt jetzt auf die nächste Zeile)
- Dann den Offset des überschreibenden chars zu den gespeicherten fptr 
aus START addieren und damit (in fptr) dann f_putc aufrufen.
- gesicherten fptr zurück in die Struktur und wieder von vorn bis 
Dateiende.
- Datei schließen und alles ist so wie es sein soll.

Und den ganzen Block Kram vergessen. Der große Meister kümmert sich 
drum. ;-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.