CODESYS - CSV aus String mit SysFileWrite - NUL am Ende jeder Zeile?

LMDaniel999

Level-1
Beiträge
57
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

ich möchte eine Protokollierung mit Hilfe von Codesys V3 auf dem Raspberry Pi umsetzen.
Dazu sollen CSV oder TXT Dateien geschrieben werden.

Da es um mehrere tausend Messwerte in einer Datei geht, habe ich mittlerweile ein STRING Array erzeugt, welches ich mit SysFileWrite schreibe.
Das klappt auch soweit gut.
(Ein einzelner STRING war zu kurz. Wenn ich nacheinander schreiben wollte, hat der die alten Werte überschrieben.)

Ich habe mittlerweile nur ein Problem, was ich nicht lösen kann:
Am Ende jeder Zeile habe ich nach dem CR LF noch einmal ein NUL.
Ich habe die Stringlänge pro Zeile auf 7 gestellt, damit ich 5 Zeichen für den Messwert und 2 Zeichen für CR LF habe.
Wenn ich 6 Zeichen pro String habe, schneidet er das LF ab. Mache ich 8 Zeichen, kommt ein NUL dazu.

Woher kommt das einzelne NUL?

PS: Wenn ich ungleichlange Strings in jeder Zeile habe, wie bekomme ich die ungenutzten Zeichen "leer"?

Danke!
 
Bei Codesys und seinen Derivaten wird das Ende eines Strings mit NUL gekennzeichnet, daher kommt das.
Zu Deinem P.S. ermittel mit LEN die tatsächliche Länge des Strings und schreibe diese Anzahl an Zeichen in die Datei. Und vor dem Füllen den String mit :='' löschen oder, da es ja ein Array und kein einzelnes String ist, den Speicherbereich des Arrays mit 16#00 füllen.

Von irgendwas mit Internetzugang gesendet
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Was mir gerade einfällt. Schreibst Du das Array Zeilenweise oder komplett? Bei letzterem wirst Du es nicht verhindern können, dass neben dem String auch mehrere 16#00 geschrieben werden, denn dann wird ja nicht die tatsächlich vom String belegte Länge geschrieben sondern die deklarierte maximal mögliche Länge.

Von irgendwas mit Internetzugang gesendet
 
Verdammt, das habe ich befürchtet! :)
Ich hatte bei TwinCat ein ähnliches System, da war das aber nicht so.
Bekommt man die NUL irgendwie weg? Oder ist das für weitere lesende Software nicht schlimm?

Ich schreibe das Array komplett. Zeilenweise habe ich vorher versucht. Da überschreibt er mir die alten Zeilen, wenn ich die Datei offen lasse und immer wieder SysFileWrite ausführe...
Das Array komplett schreiben klappt super und total easy! Nur das Problem mit den Zeichen habe ich...

Ich könnte aber vor dem Schreiben zeilenweise die tatsächliche Zeilenlänge abfragen und den Rest des Strings mit "nichts" auffüllen, oder? (Was ist "nichts"?)
Wenn ich aktuell nämlich z.B. erst 10 Zeichen in einer Zeile hatte, danach nur 8, dann bleiben die alten Zeichen ab dem 8. Zeichen beim Exportieren anscheinend drinne.
Auch wenn ich vorher den Array mit := '' geleert habe.
 
Das das bei TC anders war kann ich mir fast nicht vorstellen, basiert ja auch auf Codesys. Wenn Dein String z.B. maximal 30 Zeichen lang ist werden halt 30 Bytes in die Datei geschrieben. Ob das ein lesendes Programm stört hängt von dem Programm ab, das kann man pauschal nicht sagen.
Ach, und nichts gibt es nicht.

Von irgendwas mit Internetzugang gesendet
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Da es um mehrere tausend Messwerte in einer Datei geht, habe ich mittlerweile ein STRING Array erzeugt, welches ich mit SysFileWrite schreibe.
Das klappt auch soweit gut.
(Ein einzelner STRING war zu kurz. Wenn ich nacheinander schreiben wollte, hat der die alten Werte überschrieben.)
Achtung! SysFileWrite schreibt nicht nur die von String-Nutzdaten belegten Bytes sondern den gesamten vom Array belegten Speicherbereich inklusive der unbelegten Lücken. Du müsstest vorher die Lücken beseitigen, z.B. durch lückenloses umkopieren in ein Byte-Array oder durch Zusammenfassen der Strings zu einem Gesamtstring mit CONCAT - allerdings können die in Codesys vorhandenen Stringfunktionen nur Strings bis maximal 255 Zeichen verarbeiten. Desweiteren mußt Du nicht die gesamte CSV-Datei im Arbeitsspeicher zusammenstellen und in einem Stück schreiben, sondern kannst/solltest in mehreren Teilstücken (z.B. zeilenweise) mit mehreren SysFileWrite-Aufrufen schreiben.

Harald
 
Hallo Harald,
leide ich jetzt an Halluzinationen? Ich dachte ich hätte auf meinem Handy in diesem Thread eine Frage von Dir gelesen in welchen Derivaten das mit dem 16#00 so sei. Hab ich mir das eingebildet?
 
Ob das Null-Byte ein Problem ist oder nicht bekommst Du am einfachsten durch einen Versuch heraus. M.W. wird das Null-Byte in csv's aber ignoriert.
Ich habe gerade mal eine meiner Protokolldateien mit ein paar Nullen gespickt. In Libre-Office werden die Klaglos geöffnet.

Edit: In meinem Twincat ermittle ich die zu schreibende Stringlänge (Size) individuell mit len(string). Ich hab da keine Nullen im csv.

len() gibt m.w. die wirkliche Stringlänge
sizeof() gibt die max. mögliche Stringlänge +1, daher vermutlich Deine nul
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Harald,
leide ich jetzt an Halluzinationen? Ich dachte ich hätte auf meinem Handy in diesem Thread eine Frage von Dir gelesen in welchen Derivaten das mit dem 16#00 so sei. Hab ich mir das eingebildet?
Hallo, nee hast Du nicht.
Ich hatte eine Frage, habe dann gleich gemerkt, daß ich da was verwechselt hatte und habe die Frage wieder gelöscht.

Harald
 
Andere Frage: Auf was für ein Medium schreibst Du in welchem Zyklus?
Hintergrund: Bei Flashmedien würde ich mir über die Zahl der Schreibzyklen Gedanken machen und dabei berücksichtigen, das Schreibzugriffe kleiner Blockgröße (meist 512Byte) immer einen kompletten Flash-Block neu schreiben. Im schlimmsten Fall wird also bei einem ein-Byte-Zugriff ein kompletter Block 512 mal gelöscht und wieder geschrieben.
 
Hallo!

Viele Antworten! :) Erstmal nacheinander jetzt:

-Vielleicht ist mir die NUL bei dem TwinCAT nicht aufgefallen. Dort habe ich csv Dateien geschrieben. Aktuell zum Testen einfach txt Dateien. Muss mal eine csv machen und in Excel öffnen.

-Ich habe zuerst versucht, einzelne Zeilen zu schreiben, indem ich immerwieder einen String neu gefüllt und mit SysFileWrite geschrieben habe. Das war aber erstens wesentlich unkomfortabler und ich hatte wie gesagt die Daten nicht sauber hinbekommen. Das kann aber auch sein, dass das an meinem "Versuchsprogramm" lag. Ich hatte zuerst die Datei mit dem ACCESS_MODE AM_WRITE offen. Da hat er mir die Daten immer wieder überschrieben. Bei AM_WRITE_PLUS hat er mir neue Zeilen angehängt, aber da waren auch immer alte Zeichen dabei.

-Aktuell nutze ich SizeOf(): Ich teste mal Len(). Möglicherweise klappt das und das löst das Problem.

-Ich schreibe aktuell auf eine SD Karte. Zum Testen erzeuge ich jede Sekunde einen neuen "Messwert" und schreibe nach 1000 Stk. Also ca. alle 15 Min. Später wird das nur 5-6 mal täglich passieren.


Was ist sinnvoller? Die Daten in Einem schreiben oder zeilenweise?
Wenn ich die 1000 Zeilen einzeln schreibe brauche ich wesentlich länger, da ich ja pro Zyklus nur eine Zeile schreibe.

Danke!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Das mit den alten Zeichen ist, soweit Du mit SIZEOF arbeitest, logisch. Wenn Du einem String einen neuen Wert zuweist und dieser kürzer als der Alte ist bleiben die Reste des alten Eintrags erhalten und werden dann auch geschrieben. Bei LEN würde er nur die Anzahl der Zeichen des aktuellen Wertes schreiben. Deswegen war mein Vorschlag mit :='' auch Blödsinn, sorry. Hier hilft nur vorher den Speicherbereich mit 16#00 zu überschreiben.

Von irgendwas mit Internetzugang gesendet
 
Genau.
Nur kann ich den LEN Befehl nicht nutzen, wenn ich das Array schreibe. Nur, wenn ich Zeilen schreibe. Beim Array habe ich halt zwischen den einzelnen Zeilen dann die alten Zeichen. Ich müsste den ganzen Array erst leeren.

Ich würde erstmal beim ganzen Array bleiben, es sei denn es finden sich gute Argumente, das Zeilenweise zu machen.
 
Die Lösung ist da! :)

Also das NUL ist in der CSV weg. da zeigt er mir die Werte schön untereinander an. War bei der TXT Datei nicht so.
Im Notepad+ sind sie zwar noch da, aber auch Excel öffnet das ohne Probleme.

Nach 1000 Messwerten sucht mein Programm den nächsten freien Dateinamen (mit fortlaufenden Nummern) und schreibt dann unter dem Namen eine CSV Datei mit allen 1000 Werten hin.
Den Speicherbereich des Arrays überschreibe ich nicht, da ich pro Zeile immer 5 Zeichen Messwert + 2 Steuerzeichen habe. Somit habe ich einen Array mit 1000 STRINGS der Länge 7.
Wird also vom neuen Messwert komplett überschrieben. Das klappt super, bis auf das eine NUL am Ende. Aber hat sich ja rausgestellt, dass es gar nicht stört!

Danke nochmal an alle!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich gruppiere bei mir die einzelnen String-Zeilen in einem Bytearray (>1kByte). Dabei bestimme ich bei jeder Zeile die Stringlänge mit len() und zähle dementsprechend den Arrayindex hoch. Auf diese Art schreibe ich nicht ein unnützes Nul in meine Datei, weil ich immer genau weiß, wie lang das Array ist. Die einzelnen Stringlängen können bei mir variieren, da die meine Meßwerte ein- bis sechsstellig sein können.
Dieses Array schreibe ich dann immer in einem Rutsch, wenn der Arrayindex >1024 ist. Das Array hat natürlich noch einen "Sicherheitspuffer".
Zeilenweises Schreiben verursacht mir zu viele Schreibzugriffe und dauert viel länger.

Da meine Meßwerte mit Zeitindex gespeichert werden, habe ich "Tagesdateien" gebildet. Dabei ist das Datum der Dateiname. Da es für mich nicht so wichtig ist, endet dabei eine Datei nicht um 23:59:59, sondern schreibt den Block komplett und fängt ggf die nächste Datei erst mit dem darauffolgenden Block an.
Das mit den Tagesdateien ist mir für Übersichtsdiagramme wichtig, die ich so mal eben schnell in Excel machen kann.
 
Schrieb ich auch schon: die Strings lückenlos in ein Byte-Array umkopieren.
Die NUL-Bytes und anderen "nicht störenden" Müll mit in die csv-Datei schreiben ist Murks. Auch wenn in Windows-for-Idiots alles schick aussieht.

Harald
 
Hi.
Das mit dem Byte Array ist vielleicht echt ne gute Sache.
Ich lass es erstmal so, bis der Rest läuft und ändere dann meine Speicher Routine.
Es ist ja noch ein Zeitstempel in der CSV geplant.
Daher kann ich dann auch mehr Messwerte zusammenfassen.

Der Raspberry hängt aktuell nicht am Netzwerk.
Daher möchte ich NOCH keine Dateien mit Datum machen und keine Zeitstempel einfügen, da das ja dann eventuell nicht stimmen kann.
Habe gelesen, dass der erst einen Zeitserver brauch, da er die Uhrzeit verliert. Aber getestet habe ich das noch nicht, da er bei mir zum Programmieren eh am Netzwerk hängt.
Später in der Anwendung erstmal nicht. Eventuell kommt die Einbindung in ein Netzwerk.
 
Zurück
Oben