Skript zur Variablenarchivierung --> Performanceproblem

J_uri

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

ich nutze zur Variablenarchivierung ein Skript, das vom Aufgabenplaner minütlich gestartet werden soll. Es schreibt eine Zeile in eine CSV-Datei, die als Umlaufarchiv dient. Das Projekt läuft auf einer Workstation als Runtime.

Ich habe das Problem, dass diese Prozedur scheinbar sehr viele Ressourcen benötigt, so dass es wohl zu einer Art Überlauf kommt und manche andere Aufgaben des Aufgabenplaners nicht mehr durchgeführt werden. Meine CPU-Leistung steigt bei der RT-Simulation auch stark an (ohne minütliche Speicherung: ca. 10 %, mit minütlicher Speicherung: ca. 80 %).

Ich habe meinen Code angehangen. Gibt es eine Möglichkeit den performanter zu machen? Ich vermute, dass die Variablenzugriffe das Problem sind. Aber wie kann man die anders gestalten? Als Array o. ä.?

Vielen Dank.

Code:
Dim fso, f, ts, DataSet, Header, FName, LineData

' Archivierungspfad (Eingangsparameter) und Dateiname zusammensetzen 
' Combine archivepath (input parameter) an filename
FName = StoragePath & ArchiveName & ".csv"

If SmartTags("FileLines") => MaxLines Then
    DeleteLine FName,"",4,0
End If

' Tabellenkopf zusammenstellen (Spalten Tag_10; Tag_11 usw.)
' Chr(10) = ANSI-Code für Zeilenvorschubzeichen
' Create table header (Column for Tag_10; Tag_11 and so on)
 Header = "Column1;Column2;Column3..." & Chr(10)

' FileSystemObject erstellen
Set fso = CreateObject("Scripting.FileSystemObject")


' Wenn Datei noch nicht vorhanden ist, dann wird eine Datei erzeugt
' if the file does not exist, then create a file
If Not fso.FileExists(FName) Then   

   fso.CreateTextFile FName              
   Set f = fso.GetFile(FName)         
' Datei dem Skript als Objekt zur Verfügung stellen
' File as Object available for script

   Set ts = f.OpenAsTextStream(8, -2)
' Datei öffnen
' open file

   ts.WriteLine(FName)                 
   ts.WriteLine(Header)                 
   ts.Close
' Pfad- & Dateiname und Tabellenkopf in die Datei schreiben
' write path- & filename and table header into file
' Datei schließen
' close file

End If 

 Set f = fso.GetFile(FName)            
' Die Archivdatei dem Skript als Objekt zur verfügung stellen 
' Archive file as object available for script

 Set ts = f.OpenAsTextStream(8, -2) 
' Die Datei öffnen 
' Open file
     
' Werte der Variablen in die Archivdatei schreiben
' Write values of variables in archive file

LineData = CStr(Now) & ";" & CDbl(SmartTags("Var1")) & ";" &_
                                    CDbl(SmartTags("Var2")) & ";" &_
                                    CDbl(SmartTags("Var3")) & ";" &_ 
                                    CDbl(SmartTags("Var4")) & ";" &_ 
                                    CDbl(SmartTags("Var5")) & ";" &_ 
                                    CDbl(SmartTags("Var6")) & ";" &_ 
                                    CDbl(SmartTags("Var7")) & ";" &_ 
                                    CDbl(SmartTags("Var8")) & ";" &_ 
                                    ...
                                    CDbl(SmartTags("Var78"))


ts.WriteLine(LineData)

' Aktuelle Zeile zurückgeben 
' Read last linenumber
 SmartTags("FileLines") = ts.Line
 
' Datei wieder schließen
' Close file
 ts.Close

' Verwendeten Speicher wieder freigeben
' Used storage will be freed
Set ts  = Nothing
Set LineData = Nothing
Set f   = Nothing
Set fso = Nothing
 
Ich habe meinen Code angehangen. Gibt es eine Möglichkeit den performanter zu machen? Ich vermute, dass die Variablenzugriffe das Problem sind. Aber wie kann man die anders gestalten? Als Array o. ä.?

Das Arbeiten mit einem Array in WinCC flexible wird leider keine Verbesserung bringen.

Siehe dazu die folgenden Beiträge:

http://www.sps-forum.de/showthread.php?t=48008

http://www.sps-forum.de/showpost.php?p=351162&postcount=5

http://www.spsforen.com/showthread.php?t=25678

Gruß Kai
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Kai,

vielen Dank für die Links.

Inzwischen habe ich rausbekommen, dass es scheinbar an der Größe der externen Datei liegt, die ich zeilenweise schreibe. Denn wenn diese Datei voll ist und somit in den "Umlaufmodus" wechselt (1. Zeile wird gelöscht, letzte wird neu geschrieben) dann benötigt die RT ab dem 2. Start des Skriptes enorme Rechenleistung, die auch nicht wieder runtergeht. Selbst wenn ich die Aufgabe nur alle 2 Minuten starte.

Sieht vielleicht ein kundiger Skriptprogrammierer woran das an meinem Code liegen könnte. Ich gebe ja die Dateireferenzen immer wieder frei.

Gruß
 
Hallo,
wie wäre es, wenn du die Umlauf-Geschichte so machst, dass du als erstes die Quelldatei umbenennst. Dann aus der úmbenannten Quelldatei die Zeilen 2 .. maxLines einliest und in die neue Datei (mit dem alten Namen) schreibst und dann die neue Datenzeile da anhängst.
Ich weiß nicht, ob es das wirklich besser macht - den Versuch wäre es aber m.E. wert ...

Gruß
Larry
 
Hallo Larry,

ich habe das Problem weiter eingegrenzt. Es liegt an meiner "Delete Line" Funktion. Die Funktion liest unnötigerweise jede Zeile der Datei (10080) ein, obwohl sie nur die 4. Zeile löschen soll. Ich hatte diesen Code von einem Kollegen übernommen. Er sucht auch gleichzeitig noch nach Schlagwörtern, was ich aber nicht benötige.

Gibt es eine schnellen Code, der mir genau die angegebene Zeile aus einer Textdatei löscht.

Also nach dem Motto: "Textdatei.LöscheZeile(4)" ?

Da muss es doch etwas geben.

Vielen Dank nochmal

Gruß
 
Nein, so:

Code:
'Remove line(s) containing text (strKey) from text file (strFile)
 'or
 'Remove line number from text file (strFile)
 'or
 'Remove line number if containing text (strKey) from text file (strFile)
 
 'Use strFile = "c:\file.txt"   (Full path to text file)
 'Use strKey = "John Doe"       (Lines containing this text string to be deleted)
 'Use strKey = ""               (To not use keyword search)
 'Use LineNumber = "1"          (Enter specific line number to delete)
 'Use LineNumber = "0"          (To ignore line numbers)
 'Use CheckCase = "1"           (For case sensitive search )
 'Use CheckCase = "0"           (To ignore upper/lower case characters)
 
 
    Const ForReading=1:Const ForWriting=2
    Dim objFSO,objFile,Count,strLine,strLineCase,strNewFile
    Set objFSO=CreateObject("Scripting.FileSystemObject")
    Set objFile=objFSO.OpenTextFile(strFile,ForReading)
    
    Do Until objFile.AtEndOfStream
       strLine=objFile.ReadLine
       If CheckCase=0 Then strLineCase=UCase(strLine):strKey=UCase(strKey)
       If LineNumber=objFile.Line-1 Or LineNumber=0 Then
          If InStr(strLine,strKey) Or InStr(strLineCase,strKey) Or strKey="" Then
             strNewFile=strNewFile
          Else
             strNewFile=strNewFile&strLine&vbCrLf
          End If
       Else
          strNewFile=strNewFile&strLine&vbCrLf
       End If
    Loop
    objFile.Close
    Set objFSO=CreateObject("Scripting.FileSystemObject")
    Set objFile=objFSO.OpenTextFile(strFile,ForWriting) 
    objFile.Write strNewFile 
    objFile.Close
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich nehme es zurück. Ja du hast recht. Es ist der selbe Code.

Es kann doch aber nicht sein, dass diese Prozedur den Rechner an seine Leistungsgrenze bringt. Es sind doch nur eine Schleife und 2 Dateizugriffe. In meinem Fall hat die Datei ca. 10000 Zeilen. Das sorgt für 3 min Dauerbeschäftigung... in denen keine andere Aufgabe durchgeführt wird.
 
Zuletzt bearbeitet:
wenn die zeile recht lang sind dauert das einlesen sehr lange

machs mal so das geht sehr schnell
PHP:
    Const ForReading=1:Const ForWriting=2 
    Dim objFSO,objFile,Count,strLine,strLineCase,strNewFile 
    dim zeile(15000)
    Set objFSO=CreateObject("Scripting.FileSystemObject") 
    Set objFile=objFSO.OpenTextFile(strFile,ForReading) 
    x=0
    Do Until objFile.AtEndOfStream 
       x=x+1
       zeile(x) = objFile.Readline 
    Loop 
    objFile.Close 

    Set objFSO=CreateObject("Scripting.FileSystemObject") 
    Set objFile=objFSO.createTextFile(strFile,ForWriting)
    for y=2 to x  
       objFile.Writeline zeile(y) 
    next 
    objFile.Close
 
In meinem Fall hat die Datei ca. 10000 Zeilen. Das sorgt für 3 min Dauerbeschäftigung... in denen keine andere Aufgabe durchgeführt wird.

Könntest Du die Datei mit den 10000 Zeilen mal ins Forum stellen oder falls die Datei zu groß ist mir per E-Mail schicken?

Ich würde gerne mal unterschiedlichen Programmcode mit einer Datei dieser Größe testen.

Gruß Kai
 
Zuviel Werbung?
-> Hier kostenlos registrieren
das problem ist, dass immer mit der kompletten datei gearbeitet wird. und das 10000 mal.

bei der variante die ich gepostet habe wird die datei nur einmal eingelesen und dann neu geschrieben indem man einfach die erste zeile nicht schreibt.

für diesen zweck absolut ausreichend.
 
Hallo Volker,

dein Codevorschlag ist die Rettung. Damit geht es in einem Bruchteil der Zeit. Allerdings haperts bei mir noch daran, dass dein Vorschlag den Header, der in der Datei steht mit löscht. Ich bräuchte einen Code, der immer die vierte Zeile löscht. Allerdings hat das leider nicht geholfen:

Code:
Const ForReading=1:Const ForWriting=2 
    Dim objFSO,objFile,strLine,strLineCase,strNewFile 
    Dim zeile(15000)
    Dim x, y
    Set objFSO=CreateObject("Scripting.FileSystemObject") 
    Set objFile=objFSO.OpenTextFile(strFile,ForReading) 
     x=0
    Do Until objFile.AtEndOfStream 
       x=x+1
       zeile(x) = objFile.ReadLine 
    Loop 
    objFile.Close 

    Set objFSO=CreateObject("Scripting.FileSystemObject") 
    Set objFile=objFSO.CreateTextFile(strFile,ForWriting)
    For y=0 To x  
        [B]If y<>4 Then objFile.WriteLine zeile(y) [/B]
    Next 
    objFile.Close
Anbei mal eine kleinere Datei, nur damit man sieht wie es aussieht.



@Kai:
Ich könnte dir die Datei per Mail schicken. Rechne aber nicht gleich damit... meine Verbindung ist ziemlich langsam.
 

Anhänge

  • Test.txt
    11,9 KB · Aufrufe: 12
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich bräuchte einen Code, der immer die vierte Zeile löscht. Allerdings hat das leider nicht geholfen:

Code:
Const ForReading=1:Const ForWriting=2 
    Dim objFSO,objFile,strLine,strLineCase,strNewFile 
    Dim zeile(15000)
    Dim x, y
    Set objFSO=CreateObject("Scripting.FileSystemObject") 
    Set objFile=objFSO.OpenTextFile(strFile,ForReading) 
     x=0
    Do Until objFile.AtEndOfStream 
       x=x+1
       zeile(x) = objFile.ReadLine 
    Loop 
    objFile.Close 
 
    Set objFSO=CreateObject("Scripting.FileSystemObject") 
    Set objFile=objFSO.CreateTextFile(strFile,ForWriting)
    For y=0 To x  
        [B][COLOR=red]If y<>4 Then objFile.WriteLine zeile(y) [/COLOR][/B]
    Next 
    objFile.Close

Code:
Const ForReading=1:Const ForWriting=2 
    Dim objFSO,objFile,strLine,strLineCase,strNewFile 
    Dim zeile(15000)
    Dim x, y
    Set objFSO=CreateObject("Scripting.FileSystemObject") 
    Set objFile=objFSO.OpenTextFile(strFile,ForReading) 
     x=0
    Do Until objFile.AtEndOfStream 
       x=x+1
       zeile(x) = objFile.ReadLine 
    Loop 
    objFile.Close 
 
    Set objFSO=CreateObject("Scripting.FileSystemObject") 
    Set objFile=objFSO.CreateTextFile(strFile,ForWriting)
    For y=0 To x  
        [B][COLOR=red]If y<>3 Then objFile.WriteLine zeile(y) [/COLOR][/B]
    Next 
    objFile.Close

In VBS beginnt ein Array immer mit dem Index 0.

Die 4 Zeile der Datei hat also im Array den Index 3.

Gruß Kai
 
Im obigen Programmcode von mir ist noch ein Fehler.

Das Array-Feld mit dem Index 0 wird nicht beschrieben.

Die erste Zeile der Tabelle wird in das Array-Feld mit dem Index 1 geschrieben.

Der folgende Programmcode sollte funktionieren:

Code:
Const ForReading=1:Const ForWriting=2 
    Dim objFSO,objFile,strLine,strLineCase,strNewFile 
    Dim zeile(15000)
    Dim x, y
    Set objFSO=CreateObject("Scripting.FileSystemObject") 
    Set objFile=objFSO.OpenTextFile(strFile,ForReading) 
     x=0
    Do Until objFile.AtEndOfStream 
       x=x+1
       zeile(x) = objFile.ReadLine 
    Loop 
    objFile.Close 
 
    Set objFSO=CreateObject("Scripting.FileSystemObject") 
    Set objFile=objFSO.CreateTextFile(strFile,ForWriting)
    [COLOR=red][B]For y=1 To x[/B][/COLOR]  
        [B][COLOR=red]If y<>4 Then objFile.WriteLine zeile(y) [/COLOR][/B]
    Next 
    objFile.Close

Gruß Kai
 
Hallo Kai, vielen Dank für den Tipp. Jetzt sollte es gehen. Die Datei sollte inzwischen auch bei dir angekommen sein.

Gruß
 
Hier ist nun mein Programmbeispiel für die Löschung einer Zeile in einer Textdatei.

Auf einem Rechner mit Windows XP SP3, Pentium 4 Prozessor 3 GHz und 2 GB Arbeitsspeicher dauert die Löschung der vierten Zeile
aus einer CSV-Datei mit 10084 Zeilen und 79 Spalten ungefähr 1 Sekunde.

Code:
' =================================================
' Name: DeleteLine.vbs
' Author: Kai
' Version: 1.0
' Description: Remove line number from text file
' =================================================
 
Dim objFSO, objFile
Dim strLines, arrLines
Dim intCounter
 
Const strFileName = "E:\Archive\Values.csv"
Const intLineNumber = 4
 
Const ForReading = 1
Const ForWriting = 2
 
Set objFSO = CreateObject("Scripting.FileSystemObject")
 
Set objFile = objFSO.OpenTextFile(strFileName, ForReading)
strLines = objFile.ReadAll
arrLines = Split(strLines, VbCrLf)
objFile.Close
 
For intCounter = intLineNumber - 1 To UBound(arrLines) - 1
    arrLines(intCounter) = arrLines(intCounter + 1)
Next
ReDim Preserve arrLines(UBound(arrLines) - 1)
 
Set objFile = objFSO.OpenTextFile(strFileName, ForWriting)
strLines = Join(arrLines, VbCrLf)
objFile.Write(strLines)
objFile.Close

Gruß Kai
 
Hallo zusammen,
sorry, dass ich diesen alten Thread nochmal hervorkrame. Die obigen beschriebenen Codes haben sich bewährt. Allerdings stehe ich nun vor einem weiteren Problem. Der Code oben ist für Runtimesysteme super. Allerdings funktioniert er nicht auf Panels mit WinCE (bspw. MP377). Kennt jemand ein Beispiel zur Umsetzung von Umlaufarchiven auf Panels mit VBScript? Das Schreiben in CSV-Dateien ist kein Problem, allerdings die Umsetzung der Umlauffunktion. Soweit ich sehe gibt es keine Möglichkeit sich bspw. einfach die Anzahl der Zeilen oder die aktuelle Zeile einer Textdatei auszugeben (im Runtime mit OpenAsTextStream und "*.Line" realisiert).

Vielen Dank.
Gruß Juri
 
Zurück
Oben