# txt-Datei Aufrufen,Schreiben,Speichern



## trabert91 (6 Januar 2015)

Hallo Forumgemeinde,
meine Aufgabe ist es ein Array, welches durch Codesys3.5 erstellt wurde, in eine .txt- bzw. .csv-Datei zu schreiben. Bis jetzt sind jegliche Versuche gescheitert, eine Datei zu öffnen, geschweige denn zu schreiben. Aktuell versuche ich erstmal einen String in eine Datei zu schreiben. Ich bin über jeden Hinweis bzw. Lösung sehr dankbar.

Hier der bisherige Code:

FUNCTION_BLOCK POU
VAR_INPUT
END_VAR
VAR_OUTPUT
    hFile: DWORD;
END_VAR
VAR
    R_TRIG_SAVE: R_TRIG;
    speichern: BOOL := TRUE;
    Text: STRING := 'Hallo Welt';
    anz_bytes: DWORD;
    Ergebnis: UDINT;
    Acess : ACCESS_MODE;
END_VAR

R_TRIG_SAVE(CLK:=speichern);
IF R_TRIG_SAVE.Q THEN
    hFile := SysFileOpen('c:\Neu.txt',Acess,Ergebnis);
    anz_bytes:=SysFileWrite(hFile ,ADR(Text),LEN(Text),Ergebnis);
    sysFileClose(hFile);
END_IF


----------



## LMDaniel999 (6 Januar 2015)

Hi.
Das Schreiben bzw. Lesen einer CSV Datei ist recht einfach.
Hier gibt es bei Beckhoff Infos:
http://infosys.beckhoff.com/index.p...ies/html/tcplclibutilities_csv_sample.htm&id=
Allerdings ist das glaube ich nur für TwinCAT 2. Damit habe ich es benutzt.

Du kannst dir da die Beispieldatei runterladen und diese dann nutzen. Darin sind vier Funktionen:
Je Import und Export im Binary oder im Textmode. Ich empfehle dir den Textmode.
Dort kannst du aber nur Strings lesen und schreiben. Ist aber kein Problem.
Es gibt fertige Funktionen, die dir die Datentypen hin und her wandeln.
Ich habe so auch strings, ints und reals importiert, bzw. convertiert.

Ob dein Code so auch geht, weiß ich nicht. Da bin ich noch zu kurz in TwinCat.
Aber wenn du eh einen Array einlesen und speichern willst, dann musst du in der Beispieldatei nur die Arrays anpassen.
Ich kann dir dazu auch gerne noch weiter helfen. Kein Problem!

EDIT: Ich habe jetzt erst gemerkt, dass es vermutlich gar nicht um TwinCat geht, sondern allgemein um Codesys. Sry!
Aber ich denke, dass du das Beispiel vielleicht trotzdem nutzen kannst! Zumindest kannst du da eine "Anleitung" gewinnen.


----------



## Hendrik (7 Januar 2015)

Meine Lösung in ST für TwinCat sollte aber ähnlich auch bei CODESYS brauchbar sein



```
VAR_INPUT
    b_EXECUT:BOOL;             (* Startbefehl zum Daten schreiben *)
    DateiName: STRING;            (* DateiName und Pfad auf dem Datenträger *)
    Datei: STRING [255];            (* In diesem String sind die zuschreibenden Daten *)
END_VAR
VAR_OUTPUT
    nErrID: UDINT;                (* ADS-ErrorID *)
    bError: BOOL;                    (* ErrorBool *)
    bBusy: BOOL;                    (* BusyBool *)
    SchreibenFertig: BOOL;        (* Daten schreiben fertig gestellt *)
END_VAR
VAR
    FB_FileOpen1:FB_FileOpen;    (* FB_FileOpen--> Datei erzeugen, wenn vorhanden Daten anhängen *)
    FB_FileWrite1: FB_FileWrite;    (* FB_FileWrite--> Daten im erzeugter Datei auf Datenträger schreiben *)
    FB_FileClose1: FB_FileClose;    (* FB_FileClose--> Erzeugte Datei auf dem Datenträger schließen *)
    hFile: UINT;                    (* hFile *)
    Step: INT :=0;                    (* CaseSchritte *)
    FlankeSchreiben: BOOL;        (* Stellt sicher das nur einmal geschrieben wird pro Aufruf *)
END_VAR
```


```
(**********************************************************
    Datei auf einen Datenträger schreiben
***********************************************************)

IF SchreibenFertig =TRUE THEN
    FlankeSchreiben := b_EXECUT;
    SchreibenFertig:=FALSE;
END_IF

IF b_EXECUT AND NOT FlankeSchreiben THEN                (* b_EXECUT startet den Ablauf, FlankeSchreiben sorgt dafür das die CASE Anweisung nur einmal durchlaufen wird*)


    CASE Step OF                                        (*Der CASE regelt das Öffnen,Schreiben und Schließen der Datei*)

        0:    (*Datei öffnen*)
            FB_FileOpen1.bExecute := FALSE;
            SchreibenFertig:=FALSE;
                IF b_EXECUT THEN
                    FB_FileOpen1.bExecute := TRUE;        (*FB Aufrufe sind unten unabhängig vom CASE aufgeführt*)
                    Step:= 5;
                END_IF

        5:
            FB_FileOpen1.bExecute := FALSE;

                IF NOT FB_FileOpen1.bBusy THEN
                    IF FB_FileOpen1.bError THEN            (*Wenn Error, dann Step 50 und Infomationen werden an gemeinsame VAR übergeben*)
                        nErrID := FB_FileOpen1.nErrId;
                        bError := TRUE;
                        Step := 50;
                    ELSE
                        hFile := FB_FileOpen1.hFile;
                        Step := 10;
                        FB_FileWrite1.bExecute := TRUE;
                    END_IF
                END_IF

        10:    (*Datei schreiben*)
            FB_FileWrite1.bExecute := FALSE;
                    IF NOT FB_FileWrite1.bBusy THEN
                        IF FB_FileWrite1.bError THEN        (*Wenn Error, dann Step 50 und Infomationen werden an gemeinsame VAR übergeben*)
                            nErrID := FB_FileWrite1.nErrId;
                            bError := TRUE;
                            Step := 50;
                        ELSE
                            Step:= 15;
                            FB_FileCLose1.bExecute := TRUE;
                        END_IF
                    END_IF

        15:    (*Datei schließen*)
            FB_FileCLose1.bExecute := FALSE ;
                IF NOT Fb_FileClose1.bBusy THEN
                    IF FB_FileClose1.bError THEN            (*Wenn Error, dann Step 50 und Infomationen werden an gemeinsame VAR übergeben*)
                        nErrId := FB_FileClose1.nErrId;
                        bError := TRUE;
                        Step:= 50;
                    ELSE
                        FlankeSchreiben := TRUE;
                        SchreibenFertig :=TRUE;
                        Step := 0 ;
                        hFile:=0;
                    END_IF
                END_IF

        50:
                    IF ( hFile <> 0 ) THEN
                        Step:= 4;
                    ELSE
                        ErrorSchreiben:= nErrID;
                        Step:=0;
                        bBusy:= FALSE;
                    END_IF


    
        END_CASE


            FB_FileOpen1(
                            sPathName:=  DateiName,
                            nMode:= FOPEN_MODEAPPEND  OR FOPEN_MODETEXT,
                            ePath:= PATH_GENERIC,
                            tTimeout:=t#3s);

            FB_FileWrite1(
                            hFile:=hFile ,
                            pWriteBuff:= ADR (Datei),
                            cbWriteLen:= LEN (Datei),
                            tTimeout:=t#3s );

            FB_FileClose1 (
                            hFile:= hFile ,
                            tTimeout:= t#3s,);


END_IF
```
Hey hatte die gleiche Aufgabe, habe es wie im code drüber gelöst.
wichtige ist das der String den du schreiben möchtest entsprechen aufgebaut ist 
z.b.
datum;Zeit;Wert1;Wert2;usw..;$R

hier noch ein Link von einem vll passendem Thema
http://www.sps-forum.de/codesys-und...datein-schreiben-lesen-kopieren-twincat2.html


----------



## KarlosMüller (11 Oktober 2022)

Hallo Leute, 
ich habe das Programm von einem Kollegen übernommen indem er genau den oben stehenden Code implementiert hat. 
Nun habe ich folgendes Problem: 
Die Daten die in meine Datei geschrieben werden sind maximal 255 Zeichen lang, müssten aber länger sein! 
Programmcode sieht folgender maßen aus: 


> Code:
> 
> FUNCTION_BLOCK FB_LogASCII
> VAR_INPUT
> ...





> Baustein Inhalt:
> 
> (**********************************************************
> Datei auf einen Datenträger schreiben
> ...





> Die Daten die in die Datei geschrieben werden sollen werden als String (9999) aneinander gehängt und dann über ADR und einen Pointe auf ein Array geschrieben:
> 
> IF QDAS_Pfad = '' THEN
> RETURN;
> ...



Wenn ich in die Datei einfach einen String einfüge in den in selbst etwas reinschreibe (z.B.: 123456789_123456789_...) dann sehe ich, dass die Datei locker mit 500 Zeichen gefüllt werden kann. Aber wenn ich den String über CONCAT(StringInhalt, 'Kxy/n) beschreibe hört er irgendwann auf und schreibt nur bis zur Hälfte der Daten und das sind (zufällig?) knapp 255 Zeichen.

Jedenfalls dachte ich, es wäre das Einfachste zwei Strings zu nutzen und die nacheinander in die Datei zu schreiben. Aber dafür blick ich den Programmcode zu wenig. 

Vielleicht entdeckt ja jemand einen Fehler oder hat eine Lösung für mich?

Vielen Dank,

K.


----------



## Oberchefe (11 Oktober 2022)

Wie sieht dein Aufruf des FB aus? Speziell was für ein Datentyp ist bei "IarDatei" beschaltet?
Welches Concat meinst du?
Stringfunktionen(wie z.B. Concat) sind bei Codesys begrenzt was die maximale Zeichenanzahl angeht.


----------



## KarlosMüller (12 Oktober 2022)

Also der Aufruf sieht so aus:


> IF QDAS_Pfad = '' THEN
> RETURN;
> END_IF
> 
> ...


und auf IarDatei wird der Pointer des StringInhalts (QDAS_DateiInhalt) geschrieben. 
Die auskommentierte Zeile 6 (//QDAS_DateiPointer := ADR(QDAS_DateiInhalt2) war mein Versuch zwei Strings auf den Pointer zu geben und zwei mal hinter einander in die Datei zu schreiben. Aber das ist eben nicht Datenkonsistent und vom Kunden unerwünscht. 

Das Vorgehen Schritt für Schritt sieht so aus:
1. Daten auf einen String(9999) schreiben:
QDAS_DateiInhalt := '';
QDAS_DateiInhalt := CONCAT(QDAS_DateiInhalt, 'XY_50050');
QDAS_DateiInhalt := CONCAT(QDAS_DateiInhalt, '$0D$0A');

QDAS_DateiInhalt := CONCAT(QDAS_DateiInhalt, 'XY_50051');
QDAS_DateiInhalt := CONCAT(QDAS_DateiInhalt, GVL_Config.Var1.Number);
QDAS_DateiInhalt := CONCAT(QDAS_DateiInhalt, '$0D$0A');

QDAS_DateiInhalt := CONCAT(QDAS_DateiInhalt, 'XY_50055');
QDAS_DateiInhalt := CONCAT(QDAS_DateiInhalt, GVL_Config.Var2.Number);
QDAS_DateiInhalt := CONCAT(QDAS_DateiInhalt, '$0D$0A');
 usw. ungefähr 25 solcher Zeilen werden in die Datei geschrieben. 

2. Der Baustein in dem das Passiert wird aufgerufen, wenn die Bedingung erfüllt sind

3. Der Pfad wird übergeben und der Baustein für das Schreiben der Datei wird aufgerufen
QDAS_Pfad := 'C:\Users\Administrator\Desktop\QDAS\GS\';
QDAS();

4. Dann kommt das, was oben im Programmcode steht.

und bei fbQDAS(IxExecute... 
kommt der Programmcode von 
**********************************************************
   Datei auf einen Datenträger schreiben
***********************************************************

und dann wird die Datei erstellt und sieht so aus, als würde der Pointer nach dem String mit 255 Zeichen einfach auf Dinge Zeigen, die mich gar nicht interessieren, also Adressbereiche übergeben, in denen keine Strings stehen, denn der Code der da in die Datei geschrieben wird ist unerleserlich, also so:

fÓg\ðØ aaWÑ[ñvæVXœlaxq`6/{<çše±áóÖ4$ƒ¦ƒqà3sf ï ×5[íOQËÐÎÁŠ$-¨q:Ý>#gMäáÁ¿VohD•S«þÉ»nxòsŠ:Q5Je[Ó¹¯+‚5½Hì«„sL”ìV<»Mìiš"¢gWHjŽÕ©‡ú»<=/(D‚šdÀ7Ù{5—«…lÆ„jî;é¸xDŠ«ê‚W‚Az”"…5ÊyÃû¡¤Ü.À‘Vú¯_Ïb‘þ    ÿz¨‡Ú4ì^óñ?W¦$&èóÈd$”ÎueåžÙ9!µ›Ö9Ð·äx“1ìŽY:aNI„•Ý–{`ÇÈÜSÍ[¿Üj¨(Eÿ…ö,0ýXñ~bÄµ.°Hµ_ºI`ÿ¼#ºÖc)S“tþ³ñ1³“†g:«ËMûiú°ÿO´õ:±¼ç©¾C‚ÒC[Qˆ(÷T"|êÙ¬ôÓKCR«¿Ë

😭


----------



## StructuredTrash (12 Oktober 2022)

Oberchefe schrieb:


> Stringfunktionen(wie z.B. Concat) sind bei Codesys begrenzt was die maximale Zeichenanzahl angeht.


Bei Beckhoff auf 255 Zeichen, ich denke das wird bei Codesys genauso sein. Du musst Dir wohl eine eigene CONCAT-Funktion schreiben.


----------



## KarlosMüller (12 Oktober 2022)

StructuredTrash schrieb:


> Du musst Dir wohl eine eigene CONCAT-Funktion schreiben.


na das klingt ja nach einem sehr einfachen Plan =P 
Wenn ich jetzt wüsste, wie das geht?
Oder ich versuche es erstmal mit 2 getrennten Strings und schreib die nacheinander in die Datei.
Das klingt für mich irgendwie einfacher oder irre ich mich da? 
Hat nur leider bisher nicht geklappt...


----------



## PN/DP (12 Oktober 2022)

KarlosMüller schrieb:


> > VAR_IN_OUT
> > IarDatei : ARRAY[*] OF STRING(1);
> > END_VAR
> 
> ...


Was hast Du mit dem rot markierten Code gewollt? Was ist ein `ARRAY[*] OF STRING(1)` ? Na, ist auch egal, siehe unten.



KarlosMüller schrieb:


> denn der Code der da in die Datei geschrieben wird ist unerleserlich, also so:
> 
> fÓg\ðØ aaWÑ[ñvæVXœlaxq`6/{<çše±áóÖ


Beachte, der FB_FileWrite schreibt keine Strings, sondern den Inhalt eines Speicherbereiches der bei pWriteBuff beginnt und cbWriteLen lang ist, egal ob der Speicher lückenlos und vollständig mit gewollten Daten belegt ist. Der Inhalt von Strings ist meistens kürzer als der Speicherplatz den der String belegt.
Du müsstest Deine Strings lückenlos hintereinander (ohne die 0 am Ende der Strings) in einen CHAR- oder BYTE-Puffer kopieren und diesen Puffer und dessen mit Text belegte Länge an FB_FileWrite übergeben.



KarlosMüller schrieb:


> StructuredTrash schrieb:
> 
> 
> > Bei Beckhoff auf 255 Zeichen, ich denke das wird bei Codesys genauso sein. Du musst Dir wohl eine eigene CONCAT-Funktion schreiben.
> ...


Hier findest Du mehrere Varianten, wie man Strings in einen großen Puffer zusammenkopiert:





						String Array in Textdatei speichern
					

Hi,  ich möchte ein Array mit Strings in einer Datei mit FB_Write speichern. Klappt soweit - nur ein Haufen "Müll" wird mit gespeichert.   CASE iState OF     0: IF bExecute THEN             iState := istate +1;         END_IF              1: fbGetLocalAmsNetId.bExecute := TRUE;         IF...




					www.sps-forum.de
				




Harald


----------



## KarlosMüller (12 Oktober 2022)

> Was hast Du mit dem rot markierten Code gewollt? Was ist ein ARRAY[*] OF STRING(1) ? Na, ist auch egal, siehe unten.


Also, wie gesagt, is nicht mein Code! Hab die Anlage von einem Kollegen übernommen. 

Ich schau mir den anderen thread mal an, vielen Dank =)


----------



## oliver.tonn (12 Oktober 2022)

Geht es um natives Codesys, oder um eine von einem SPS-Hersteller angepasste Variante?
Manche Hersteller, z.B. Beckhoff haben neue Stringfunktionen hinzugefügt, die mehr als 255 Zeichen handhaben können.


----------



## PN/DP (12 Oktober 2022)

In dem von mir verlinkten Thread hatte StructuredTrash schon empfohlen


StructuredTrash schrieb:


> Schau Dir lieber mal die eweiterten Stringfunktionen in der Tc2 Utilities Lib an, die können Strings mit bis zu 10000 Zeichen verarbeiten.



Harald


----------



## StructuredTrash (12 Oktober 2022)

@KarlosMüller:
Sorry, da Du ja bereits mit Pointern hantierst, habe ich angenommen, daß Du schon etwas tiefer in der Materie steckst. Ich muß aber auch zugeben, daß ich oft erst ein wenig warmlaufen muß, bevor sich meine ganze Hilfsbereitschaft entfaltet. Freundlicherweise hat Harald ja schon einen Thread verlinkt, in dem Du wohl fündig wirst.


----------



## KarlosMüller (12 Oktober 2022)

Bei mir geht es um TwinCat3 von Beckhoff
Aber damit arbeite ich erst seit einem Monat, deswegen kenn ich mich noch nicht so damit aus. 
Aber ich schau danach mal.
Der Ersteller des Programms dachte wohl, dass das einfach geht mit einem String(9999) aber es scheint nicht so einfach zu gehen mit CONCAT


----------



## oliver.tonn (12 Oktober 2022)

KarlosMüller schrieb:


> Bei mir geht es um TwinCat3 von Beckhoff
> ...
> Der Ersteller des Programms dachte wohl, dass das einfach geht mit einem String(9999) aber es scheint nicht so einfach zu gehen mit CONCAT


Geht es ja auch, allerdings nur mit dem richtigen CONCAT. Wie hier schon mehrfach erwähnt bietet Beckhoff erweiterte String-Funktionen. Schau mal hier im Infosys nach CONCAT2.


----------



## KarlosMüller (14 Oktober 2022)

Also vielen Dank schon mal @oliver.tonn und @PN/DP 
ich sitze gerade noch an einem anderen Problem, aber nächste Woche werde ich es noch mal versuchen. 
Schönes Wochenende euch


----------

