# aus Flexibel heraus eine TXT Datei ändern



## rostiger Nagel (22 Januar 2011)

Hallo,
ich habe eine Flexibel RT und möchte in einer Text Datei einfach ein paar
Werte hinzufügen. Ich habe eine Datei mit Tagesproduktion, die natürlich
jeden Tag unterschiedlich lang ist. Jede Zeile enthält die Information für
ein Werkstück. Hier ein paar Zeilen.


```
1101;551;1253792;000;99;SOL01   ;  LC      ;SOCKELTEIL;  LC      ;00001;45.00               ;2                   ;26                  ;K                   ;K                   ;S                   ;S                   ;0.00000             ;0.00000             ;600.00000           ;00001;
1101;551;1253792;000;99;SOL01   ;  NN      ;SOCKELTEIL;  NN      ;00001;45.00               ;3                   ;26                  ;K                   ;K                   ;S                   ;S                   ;0.00000             ;0.00000             ;1200.00000          ;00002;
1101;551;1253792;000;99;SOL01   ;  LC      ;SOCKELTEIL;  LC      ;00001;45.00               ;4                   ;26                  ;K                   ;K                   ;S                   ;S                   ;0.00000             ;0.00000             ;600.00000           ;00003;
1101;551;1262810;000;99;SOL01   ;  ER      ;SOCKELTEIL;  ER      ;00001;45.00               ;1                   ;13                  ;K                   ;K                   ;S                   ;S                   ;0.00000             ;0.00000             ;900.00000           ;00004;
1101;551;1262810;000;99;SOL01   ;  ER      ;SOCKELTEIL;  ER      ;00001;45.00               ;2                   ;13                  ;K                   ;K                   ;S                   ;S                   ;0.00000             ;0.00000             ;600.00000           ;00005;
1101;551;1262810;000;99;SOL01   ;  ER      ;SOCKELTEIL;  ER      ;00001;136.00              ;3                   ;13                  ;K                   ;K                   ;S                   ;S                   ;0.00000             ;0.00000             ;1800.50000          ;00006;
1101;551;1262810;000;99;SOL01   ;  ER      ;SOCKELTEIL;  ER      ;00001;45.00               ;4                   ;13                  ;K                   ;K                   ;S                   ;S                   ;0.00000             ;0.00000             ;900.00000           ;00007;
1101;551;1263360;000;99;SOL01   ;  LC      ;SOCKELTEIL;  LC      ;00001;45.00               ;1                   ;28                  ;K                   ;K                   ;S                   ;S                   ;0.00000             ;0.00000             ;1050.50000          ;00008;
```
 
wenn jetzt das entsprechende Werkstück abgearbeitet ist möchte ich das
einfach, mit einen Hacken kenzeichnen und dann in der Datei mit "1" oder
"0" anhängen.


```
1101;551;1253792;000;99;SOL01  .....           ;00001;[COLOR=red]1;[/COLOR]
1101;551;1253792;000;99;SOL01  .....           ;00002;[COLOR=red]1;[/COLOR]
1101;551;1253792;000;99;SOL01  .....           ;00003;[COLOR=red]0;[/COLOR]
1101;551;1262810;000;99;SOL01  .....           ;00004;
1101;551;1262810;000;99;SOL01  .....           ;00005;[COLOR=red]1;[/COLOR]
1101;551;1262810;000;99;SOL01  .....           ;00006;
1101;551;1262810;000;99;SOL01  .....           ;00007;[COLOR=red]1;[/COLOR]
1101;551;1263360;000;99;SOL01  .....           ;00008;
```
 
in der Praxis sieht das dann so aus:









Das Detei auslesen oder neu schreiben ist nicht das Problemm, aber wie 
mache ich das wenn ich mitten in der Datei, am Ende etwas dranhängen
möchte?

Ich währe für jeden Tip dankbar

gruß Helmut


----------



## Rainer Hönle (22 Januar 2011)

Das ist ein grundsätzliches CSV-Problem. Da geht nur komplett Einlesen, Ändern und Neuschreiben. Außer WCF hätte Funktionen die das kapseln.


----------



## rostiger Nagel (22 Januar 2011)

Ok, aber wie kann ich den kompletten Dateininhalt zwischenspeicher?
Oder kann (muss) ich im Script selber zwei Dateien gleichzeitig offen halten,
so das ich Zeile für Zeile lese und in die andere Datei speichere?


----------



## PN/DP (22 Januar 2011)

Helmut_von_der_Reparatur schrieb:


> Ok, aber wie kann ich den kompletten Dateininhalt zwischenspeicher?


Mit der ReadLine-Methode in ein Zeilen-Array einlesen. ReadLine liest genau eine Zeile aus einer Textdatei.
Die ReadAll-Methode (die ganze Datei in eine VBS-Variable lesen) kann ich nicht empfehlen, da programmierst Du Dich dann bei der Verarbeitung zu Tode...

ReadLine und WriteLine sind in der WinCCflex-Hilfe sehr schön mit Beispiel erklärt. Volkers FAQ zum Dateien lesen und schreiben kennst Du ja auch.



Helmut_von_der_Reparatur schrieb:


> Oder kann (muss) ich im Script selber zwei Dateien gleichzeitig offen halten,
> so das ich Zeile für Zeile lese und in die andere Datei speichere?


Ich würde die Datei Zeile für Zeile einlesen, vergleichen ob es die gesuchte Zeile ist, wenn ja das Zeilenende ändern, dann die Zeile (geändert oder ungeändert) in eine zweite Datei schreiben. Wenn immer nur eine Zeile zu ändern ist, dann können nach der Änderung alle restlichen Zeilen ohne weitere Prüfung kopiert werden.
Zuerst noch die Eingabe-Datei umbenennen und die Ausgabe-Datei mit dem ursprünglichen Name der Eingabe-Datei anlegen.

Ich meine, die ganze Datei auf einmal in ein Zeilen-Array einlesen und dann durchsuchen und ändern ist aufwendiger zu programmieren als die zeilenweise Verarbeitung, benötigt auch mehr Arbeitsspeicher, könnte dafür aber eventuell schneller sein.
Man muß aber auf jeden Fall mit 2 Dateien arbeiten, entweder gleichzeitig oder nacheinander. Meines Wissens nach ist es unter VBS nicht möglich, eine Datei für Lesen und Schreiben zu öffnen, nur für nur Lesen oder nur Schreiben, weil Dateien als Textstream behandelt werden.

Falls Du die Zeilen in der Textdatei auch noch sortieren mußt, da eignet sich das komplette Einlesen der Datei in ein Zeilen-Array besser.

Harald


----------



## rostiger Nagel (22 Januar 2011)

Das einlesen hatte zeilenweise hatte ich heute schon probiert,
irgendwie hat das nicht hingehauen. Wenn ich das nach Volker sein
Beispiel mache:


```
Set fso = CreateObject("Scripting.FileSystemObject")
Set fs = CreateObject("WScript.Shell")
 
    Set TextFile = fso.openTextFile(datei, 1)
    x = 0
    do while textfile.atendofstream <> true
        x = x + 1
        name(x) = TextFile.readline
    loop
    textfile.close
```

Gibt es da eine beschränkung für das Array "Name" ich meine 
ist da nach 256 Zeilen Schluss oder so. 

Wenn ich es auf der Weise eingelesen habe kann ich es auch auf
der gleichen Weise mit writeLine wegschreiben. Kann ich da nicht 
die gleiche Datei nehmen und einfach überschreiben. Oder lösche 
ich die alte und erzeuge sie dann neu und Fülle sie einfach wieder
ab.


----------



## Jochen Kühner (23 Januar 2011)

Wie hasst du den dein Array Name definiert??


So sollt's gehen, da wird das Array immer wieder um 100 Element vergrößert wenn die Grenze erreicht wird!


```
Dim fso,fs,TextFile,datei,x,y,name()
datei="c:\aa.log"

Set fso = CreateObject("Scripting.FileSystemObject")
Set fs = CreateObject("WScript.Shell")
 
    Set TextFile = fso.openTextFile(datei, 1)
    x = 0
    y = 0
    Do While TextFile.atendofstream <> True
		
        x = x + 1
        If x>y Then
		y=y+100
		ReDim Preserve name(y)
	End If
        name(x) = TextFile.readline
    Loop
    TextFile.close
```


----------



## Jochen Kühner (23 Januar 2011)

*Mhmm...*

Mhmm, man sollte natürlich die Array-Startgröße so wählen das es normalerweise nicht vergrößert werden muss, da die ja immer alle Elemente wieder kopiert werden müssen. (Infos zur Performance von ReDim: http://www.vbmonster.com/Uwe/Forum.aspx/vb/11270/ReDim-Preserve-performance)

Es ist bestimmt besser schon mit einer bestimmten Größe anzufangen:


```
Dim fso,fs,TextFile,datei,x,y,name()
datei="c:\aa.log"

Set fso = CreateObject("Scripting.FileSystemObject")
Set fs = CreateObject("WScript.Shell")
 
    Set TextFile = fso.openTextFile(datei, 1)
    x = 0
    y = 1000
    ReDim name(y) ' Hier kein Preserve notwendig, array ist ja leer
    Do While TextFile.atendofstream <> True
		
        x = x + 1
        If x>y Then
		y=y+100
		ReDim Preserve name(y)
	End If
        name(x) = TextFile.readline
    Loop
    TextFile.close
```


----------



## rostiger Nagel (23 Januar 2011)

Das Array habe ich offen deklariert, liegt da der Hase begraben?


```
Dim name()
```


----------



## Jochen Kühner (23 Januar 2011)

Helmut_von_der_Reparatur schrieb:


> Das Array habe ich offen deklariert, liegt da der Hase begraben?



Das musst du, das du redim überhaupt verwenden kannst!

Also entweder offen, und mit redim größe anpassen, oder gleich fixe größe!

Infos dazu hier: http://www.asphelper.de/referenz/vbscript/redim.asp


----------



## rostiger Nagel (23 Januar 2011)

Aber ich muss die Länge dann vor der Anwendung festlegen?
Das habe ich nicht gemacht, wenn ich zeilenweise das Werkstück
mit Split zerlegt hatte, funktionierte das ohne Störung. 


```
Dim name(), zeile, wert_1, wert_2

zeile = Name(zeile)

wert_1 = zeile(1)
wert_2 = zeile(2)
```


----------



## Jochen Kühner (23 Januar 2011)

Helmut_von_der_Reparatur schrieb:


> Aber ich muss die Länge dann vor der Anwendung festlegen?
> Das habe ich nicht gemacht, wenn ich zeilenweise das Werkstück
> mit Split zerlegt hatte, funktionierte das ohne Störung.



Kein Plan, also bei mir ging's ohne eine Größenangabe gar nicht!
Aber so wie Ichs geschickt habe läufts bei mir!

Warum willst du eigentlich nicht 2 Dateien öffnen, einlesen und gleich wieder wegschreiben?

Danach killst du das Orginalfile und benennst das andere um!


----------



## PN/DP (23 Januar 2011)

Helmut_von_der_Reparatur schrieb:


> Das einlesen hatte zeilenweise hatte ich heute schon probiert,
> irgendwie hat das nicht hingehauen.


Das lag wohl an der falschen Dim-Anweisung. Ansonsten müßte Dein Code funktionieren.
Hier meine Variante:

```
Const ForReading = 1, ForWriting = 2
Dim fso, f, infile, i, zeile(1000)

Set fso = CreateObject("Scripting.FileSystemObject")
Set f = fso.OpenTextFile(infile, ForReading)
i = 0
Do While f.AtEndOfStream = False And i <= 1000
    zeile(i) = f.ReadLine
    i = i + 1
Loop
f.Close
If i > 1000 Then
	ShowSystemAlarm "Datei '" & infile & "' hat zu viele Zeilen"
	Exit Sub
End If

'...
'und schreiben dito.
```



Helmut_von_der_Reparatur schrieb:


> Gibt es da eine beschränkung für das Array "Name" ich meine
> ist da nach 256 Zeilen Schluss oder so.


Ja, es gibt eine Beschränkung. Da kommst Du aber garantiert nicht hin. 
Das Array darf reichlich 2.000.000.000 Elemente haben, außerdem darf das Array 60 Dimensionen haben ...
Entweder gleich groß genug dimensionieren oder Redim benutzen wie Jochen vorschlug.



Helmut_von_der_Reparatur schrieb:


> Wenn ich es auf der Weise eingelesen habe kann ich es auch auf
> der gleichen Weise mit writeLine wegschreiben.


Ja, genau.



Helmut_von_der_Reparatur schrieb:


> Kann ich da nicht
> die gleiche Datei nehmen und einfach überschreiben. Oder lösche
> ich die alte und erzeuge sie dann neu und Fülle sie einfach wieder
> ab.


Ich würde die Ursprungsdatei erst löschen, wenn die Ausgabedatei erfolgreich geschrieben wurde! Falls das Script aus irgendeinem Grund abschmiert ...
Auf die schnelle etwa so (kann auch anders funktionieren):
* <datei>.bak zu <datei>.txt umbenennen, falls <datei>.txt nicht existiert, aber <datei>.bak existiert (Scriptfehler!)
* <datei>.bak löschen, falls vorhanden
* <datei>.txt zu <datei>.bak umbenennen
* <datei<.bak einlesen
* <datei>.txt schreiben

PS: bin wie immer viel zu langsam, doch anscheinend gibt es nirgendwo im inet eine Angabe, wie groß ein Array in VBS sein darf. Hab's jetzt einfach in WCCflex ausprobiert. Ich spekuliere mal, daß das die Prozessor-Registerbreite - 1 ist, bei 32-Bit also 2^31 Elemente.

Harald


----------



## rostiger Nagel (23 Januar 2011)

Soll ich ja garnicht, das mit den zwei datein, war nur so
eine Idee, weil das temporäre zeischenspeichern 
nicht klappte. Dein Vorschlag werde ich morgen 
ähm heute, mal testen. Danke. 

Schönen Sonntag noch


----------



## rostiger Nagel (23 Januar 2011)

Harald, dir auch ein Danke, ich glaube ich werde mal
von beiden Versionen etwas nutzen,  einmal mit
der bak Datei und einmal mit den nachdeklarieren
bei Überschreitung.  Werde dann berichten. 

Dir auch einen schönen sonntag


----------



## PN/DP (23 Januar 2011)

Da war doch noch ein kleiner Fehler in meinem Code in #12. 
Das hätte nach der Schleife eigentlich "If i > 100*1* Then" heißen müssen.
Ich habe aber die Schleife geändert zu "And i < 1000". Das sieht besser aus, auch wenn dann ein Array-Element nicht genutzt wird.

[EDIT]
Quatsch, das war doch richtig. Habs wieder zurückgeändert.
Es ist wohl schon zu spät bzw. früh. 
Wünsche Euch noch einen schönen Sonntag.
[/EDIT]

Harald


----------



## rostiger Nagel (23 Januar 2011)

Hallo Harald, Hallo Jochen,
danke noch mal für eure Tips, jetzt Funktioniert es so wie ich es möchte.
Wie gedacht habe ich ein wenig von beiden Lössungen etwas verbaut. 
Harald sein Tip, von der Datei erst mal eine Sicherung zu ziehen, das sieht
mann aber nicht im folgenden Script, das wird beim ersten aufschlag der
Datei, in einen anderen Script durchgeführt.
Dann das von Jochen wie ich das Array richtig initalisiere und Dynamisch
erweiter, falls erforderlich.


```
Dim f, fso, Verz, Datei, Name, Endung, Pulk, Jahr, Datei_OK
Dim x, y, z
Dim Zeile, Daten
Dim Inhalt()
Const lesen = 1, schreiben = 2, anhaengen = 8
 
[COLOR=green]'Prüfen ob die Lfd_Nr aus dem Tagespulk kommt[/COLOR]
[COLOR=green]'Wenn Negativ kommt Sie nicht aus der AV[/COLOR]
If Lfd_Nr <= 0 Then Exit Sub
 
[COLOR=green]'########################################################################################[/COLOR]
[COLOR=green]'[/COLOR]
[COLOR=green]' Datei und Verzeichnis prüfen und Filesystem vorbereiten[/COLOR]
[COLOR=green]'[/COLOR]
[COLOR=green]'########################################################################################[/COLOR]
 
[COLOR=green]'Verzeichnis stellen[/COLOR]
Verz  = SmartTags("003\003-OP.Tagespulk_Verzeichnis")
 
[COLOR=green]'Prüfen ob Tagespulk eingetragen[/COLOR]
If SmartTags("003\003-OP.Tagespulk_EAUF_Nr") = "" Then
 ShowSystemAlarm "Datei nicht ausgewählt"
 Exit Sub
End If
 
[COLOR=green]'Prüfen ob Jahr eingetragen[/COLOR]
If SmartTags("003\003-OP.Tagespulk_Jahr") = "" Then 
 ShowSystemAlarm "Datei nicht ausgewählt"
 Exit Sub
End If
 
[COLOR=green]'Filesystem öffnen[/COLOR] 
Set fso = CreateObject("Scripting.FileSystemObject")
 
[COLOR=green]'Verzeichnis prüfen[/COLOR]
If Not fso.FolderExists(Verz) Then 
 ShowSystemAlarm "Verzeichnis nicht vorhanden"
 Exit Sub
End If
 
[COLOR=green]'Datei prüfen[/COLOR]
For Each Datei In fso.GetFolder(Verz).Files
 Name = Datei.Name
 Endung = Right(Name,3)
 
 Pulk = Left(Name,4)
 Jahr = Mid(Name,6,4)
 Datei_OK = False
 If Endung = "TXT" Or Endung = "txt" Then
   If Pulk = SmartTags("003\003-OP.Tagespulk_EAUF_Nr") Then
    If Jahr = SmartTags("003\003-OP.Tagespulk_Jahr") Then
    Datei_OK = True
    Exit For
   End If
  End If
 End If
Next
 
[COLOR=green]'Datei nicht vorhanden, Script beenden[/COLOR]
If Datei_OK = False Then
 ShowSystemAlarm "Datei nicht vorhanden"
 Exit Sub
End If
 
[COLOR=green]'Pfad OK, Pfad für den Tagespulk stellen[/COLOR]
Pulk = Verz & "\" & Name
 
[COLOR=green]'########################################################################################[/COLOR]
[COLOR=green]'[/COLOR]
[COLOR=green]'Datei auslesen und eintrag prüfen[/COLOR]
[COLOR=green]'[/COLOR]
[COLOR=green]'########################################################################################[/COLOR]
 
[COLOR=green]'Filesystem zum lesen öffnen[/COLOR]
Set f = fso.OpenTextFile(Pulk,lesen,False)
 
[COLOR=green]'Variabeln stellen[/COLOR]
x = 1
y = 1000
ReDim Inhalt(y)
 
[COLOR=green]'Datei bis zum Ende auslesen[/COLOR]
Do While f.AtEndOfStream <> True
 
[COLOR=green]'Zeile lesen und zwischenspeichern[/COLOR]
 Zeile = f.ReadLine
 Inhalt(x) = Zeile
 
[COLOR=green]'Zeile zerlegen und kontrollieren[/COLOR]
[COLOR=green]'ob Eintrag "bearbeitet" dabei ist[/COLOR]
 Daten = Split(Zeile,";")
 If Lfd_Nr = CLng(Daten(20)) Then
  If bearbeitet = True Then
   Daten(21) = "1"
  Else
   Daten(21) = "0"
  End If
 Else
  If Daten(21) = "" Then Daten(21) = "0"
 End If
 
[COLOR=green]'Zeile neu zusammen setzen[/COLOR]
 Zeile = "" 
 For z = 0 To 21 
  Zeile = Zeile & Daten(z) & ";"
 Next  
 
[COLOR=green]'kontrolle ob zwischenspeicher "Inhalt" voll[/COLOR]
[COLOR=green]'ist, wenn ja Array erweitern[/COLOR]
 If x > y Then
  y = y+100
  ReDim Preserve Inhalt(y)
 End If
 
[COLOR=green]'Zeile zwischenspeichern[/COLOR]
 Inhalt(x) = Zeile
 
[COLOR=green]'index erhöhen[/COLOR]
 x = x+1
 
Loop
 
[COLOR=green]'Datei schließen[/COLOR]
f.Close 
 
[COLOR=green]'########################################################################################[/COLOR]
[COLOR=green]'[/COLOR]
[COLOR=green]'Datei zurrückspeichern[/COLOR]
[COLOR=green]'[/COLOR]
[COLOR=green]'########################################################################################[/COLOR]
 
[COLOR=green]'Filesystem für das Schreiben vorbereiten[/COLOR]
Set f = fso.OpenTextFile(Pulk,schreiben,False)
z = x-1
x = 1
Do While x <= z
 f.WriteLine (Inhalt(x))
 x = x+1
Loop
 
[COLOR=green]'Datei schließen[/COLOR]
f.Close
```
 
schönen Sonntag noch
gruß Helmut


----------



## Jochen Kühner (23 Januar 2011)

Warum machst du den das Prüfen ob die Datei existiert so umständlich?

Setz dir doch einfach einen String mit deinem Namen wie er geraden lauten soll zusammen und prüfe dann mit "FileExists" des FileSystem-Objektes!

Aber wenn's geht ist ja gut...

Dir auch nen schönen Sonntag


----------



## rostiger Nagel (23 Januar 2011)

Jochen Kühner schrieb:


> Warum machst du den das Prüfen ob die Datei existiert so umständlich?


 
Einfach kann ja jeder 
Ich schau mir das noch mal an, da gibt es bestimmt etwas zu verbessern.


----------

