txt-Datei Aufrufen,Schreiben,Speichern

trabert91

Level-1
Beiträge
1
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
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
 

Anhänge

  • Codesys online.JPG
    Codesys online.JPG
    132 KB · Aufrufe: 73
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.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Meine Lösung in ST für TwinCat sollte aber ähnlich auch bei CODESYS brauchbar sein


Code:
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
Code:
(**********************************************************
    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
 
Zuletzt bearbeitet:
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
IxExecute : BOOL; (* Startbefehl zum Daten schreiben *)
IsPfad : STRING; (* DateiName und Pfad auf dem Datenträger *)
ItstTimestruct : TIMESTRUCT; (* Datum und Uhrzeit der Messung *)
IsUrsprung : STRING; (* Führt den Dateinamen an *)
IsDateiTyp : STRING := '.txt'; (* Dateiendung (bspw. .txt oder .dfq) *)
END_VAR
VAR_OUTPUT
QudErrID : UDINT; (* ADS-ErrorID *)
QxError : BOOL; (* ErrorBool *)
QxBusy : BOOL; (* BusyBool *)
QxDone : BOOL; (* Daten schreiben fertig gestellt *)
END_VAR
VAR_IN_OUT
IarDatei : ARRAY[*] OF STRING(1);
END_VAR
VAR
uChar : DINT;
FB_FileOpen : FB_FileOpen; (* FB_FileOpen--> Datei erzeugen, wenn vorhanden Daten anhängen *)
FB_FileWrite : FB_FileWrite; (* FB_FileWrite--> Daten im erzeugter Datei auf Datenträger schreiben *)
FB_FileClose : FB_FileClose; (* FB_FileClose--> Erzeugte Datei auf dem Datenträger schließen *)
hFile : UINT; (* hFile --> File Handle*)
uStep : UINT := 0; (* CaseSchritte *)
sDateiName : STRING;
rtExecute : R_TRIG;
END_VAR
Baustein Inhalt:

(**********************************************************
Datei auf einen Datenträger schreiben
***********************************************************)
rtExecute(CLK:=IxExecute);

IF QxError THEN
uStep := 50;
END_IF

CASE uStep OF (*Der CASE regelt das Öffnen,Schreiben und Schließen der Datei*)
0: (*Datei öffnen*)
FB_FileOpen.bExecute := FALSE;
FB_FileWrite.bExecute := FALSE;
FB_FileClose.bExecute := FALSE;

IF rtExecute.Q THEN
FB_FileOpen.bExecute := TRUE;
sDateiName := CONCAT(IsPfad,IsUrsprung);
sDateiName := CONCAT(sDateiName,'_');
sDateiName := CONCAT(sDateiName,WORD_TO_STRING(ItstTimeStruct.wYear));
sDateiName := CONCAT(sDateiName,'_');
sDateiName := CONCAT(sDateiName,WORD_TO_STRING(ItstTimeStruct.wMonth));
sDateiName := CONCAT(sDateiName,'_');
sDateiName := CONCAT(sDateiName,WORD_TO_STRING(ItstTimeStruct.wDay));
sDateiName := CONCAT(sDateiName,'_');
sDateiName := CONCAT(sDateiName,WORD_TO_STRING(ItstTimeStruct.wHour));
sDateiName := CONCAT(sDateiName,'_');
sDateiName := CONCAT(sDateiName,WORD_TO_STRING(ItstTimeStruct.wMinute));
sDateiName := CONCAT(sDateiName,'_');
sDateiName := CONCAT(sDateiName,WORD_TO_STRING(ItstTimeStruct.wSecond));
sDateiName := CONCAT(sDateiName,IsDateiTyp);

uStep:= 5;
END_IF

5:
FB_FileOpen.bExecute := FALSE;
IF NOT FB_FileOpen.bBusy THEN
hFile := FB_FileOpen.hFile;
IF hFile <> 0 THEN
uStep := 10;
FB_FileWrite.bExecute := TRUE;
ELSE
uStep := 50;
END_IF
END_IF

10: (*Datei schreiben*)
FB_FileWrite.bExecute := FALSE;
IF NOT FB_FileWrite.bBusy THEN
uStep:= 15;
FB_FileClose.bExecute := TRUE;
END_IF

15: (*Datei schließen*)
FB_FileClose.bExecute := FALSE;
IF NOT FB_FileClose.bBusy THEN
uStep:= 50;
END_IF

50:
hFile:=0;
uStep:=0;

END_CASE;

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

FB_FileWrite(hFile:=hFile ,
pWriteBuff:= IarDatei,//ADR(Datei),
cbWriteLen:= UPPER_BOUND(IarDatei,1) - LOWER_BOUND(IarDatei,1),//INT_TO_UDINT(LEN(Datei)),
tTimeout:=T#3S);

FB_FileClose(hFile:= hFile ,
tTimeout:= T#3S);

QxDone := uStep = 50;
QxBusy := uStep > 0 AND uStep < 50;
QxError := FB_FileOpen.bError OR FB_FileWrite.bError OR FB_FileClose.bError;

IF FB_FileOpen.bError THEN
QudErrID := FB_FileOpen.nErrId;
ELSIF FB_FileWrite.bError THEN
QudErrID := FB_FileWrite.nErrId;
ELSIF FB_FileClose.bError THEN
QudErrID := FB_FileClose.nErrId;
ELSE
QudErrID := 0;
END_IF
// ErrorId FileOpen
//0x703 Unbekannter oder ungültiger nMode oder ePath Parameter.
//0x70C Datei nicht gefunden. Ungültziger Dateiname oder Dateipfad.
//0x716 Keine weiteren freien File Handles.

// ErrorId FileWrite
//0x703 Invalid or unknown file handle.
//0x70E File was opened with wrong method ( e.g. with 'obsolete' FILEOPEN function block ).

// ErrorId FileClose
//0x703 Invalid or unknown file handle.
//0x70E File was opened with wrong method ( e.g. with 'obsolete' FILEOPEN function block ).
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;
END_IF


QDAS_DateiPointer := ADR(QDAS_DateiInhalt);

IF QDAS_DateiPointer = 0 THEN
RETURN;
END_IF

fbQDAS(IxExecute := QDAS_DateiErstellen,
IsPfad :=QDAS_Pfad,
IsDateiTyp := QDAS_DateiTyp,
IsUrsprung := QDAS_Stationsbezeichnung,
ItstTimestruct := DT_TO_SYSTEMTIME((GVL_Master.dtSystemzeit)),
IarDatei := QDAS_DateiPointer^);

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.
 
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.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Also der Aufruf sieht so aus:
IF QDAS_Pfad = '' THEN
RETURN;
END_IF

QDAS_DateiPointer := ADR(QDAS_DateiInhalt);
//QDAS_DateiPointer := ADR(QDAS_DateiInhalt2);

IF QDAS_DateiPointer = 0 THEN
RETURN;
END_IF

fbQDAS(IxExecute := QDAS_DateiErstellen,
IsPfad :=QDAS_Pfad,
IsDateiTyp := QDAS_DateiTyp,
IsUrsprung := QDAS_Stationsbezeichnung,
ItstTimestruct := DT_TO_SYSTEMTIME((GVL_Master.dtSystemzeit)),
IarDatei := QDAS_DateiPointer^);
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«¿Ë

😭
 
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...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
VAR_IN_OUT
IarDatei : ARRAY[*] OF STRING(1);
END_VAR
FB_FileWrite(hFile:=hFile ,
pWriteBuff:= IarDatei,//ADR(Datei),
cbWriteLen:= UPPER_BOUND(IarDatei,1) - LOWER_BOUND(IarDatei,1),//INT_TO_UDINT(LEN(Datei)),
tTimeout:=T#3S);
Was hast Du mit dem rot markierten Code gewollt? Was ist ein ARRAY[*] OF STRING(1) ? Na, ist auch egal, siehe unten.

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.

Bei Beckhoff auf 255 Zeichen, ich denke das wird bei Codesys genauso sein. 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?
Hier findest Du mehrere Varianten, wie man Strings in einen großen Puffer zusammenkopiert:

Harald
 
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 =)
 
@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.
 
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
 
Zuviel Werbung?
-> Hier kostenlos registrieren
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.
 
Zurück
Oben