Dateiinhalte lesen, teil ersetzen, weiterlesen...

  • Hallo liebe Community,

    Ich will zur Zeit ein logfile auslesen ( 370000 Zeilen).
    Dabei brauche ich nur bestimmte Teile des Logfiles ( immer der selbe String).

    Hier mal das momentane Script:

    Spoiler anzeigen
    [autoit]

    #include <Constants.au3>
    #include <SQLite.au3>
    #include <SQLite.dll.au3>
    #include <Arraymore.au3>
    #include <Array.au3>
    _SQLite_Startup()
    $t = _SQLite_Open(@ScriptDir & "\" & "Datenbank.db")
    $path = "C:\Temp\20111107.log"
    $hFile = FileOpen($path, 0)
    $read = FileRead($hFile)
    $Splitcount = StringSplit($read, "Trennstring", 1)
    $cnt = $Splitcount[0]
    $Splitcount = ""
    ProgressOn("Log Datei lesen", "Log Datei wird eingelesen")
    For $i = 1 To $cnt+1
    ProgressSet($i/($cnt+1) * 100)
    $findkamp = StringInStr($read, "Trennstring", 0, $i)
    If @error = 1 Or $findkamp = 0 Then
    ProgressOff()
    Exit
    EndIf
    FileSetPos($hFile, $findkamp - 77, $FILE_BEGIN)
    $Time = FileRead($hFile, 19)
    $find2 = StringInStr($read, "Statistic:", 0, 1, $findkamp, 150)
    If $find2 <> "" Then
    $Timesplit = Stringsplit($Time, " ")
    $Date = $Timesplit[1]
    $Uhrzeit = $Timesplit[2]
    $findlast = StringInStr($read, "RunningTime", 0, 1, $find2 + 13)
    FileSetPos($hFile, $find2 + 13, $FILE_BEGIN)
    $readinhalt = FileRead($hFile, $findlast - 5 - $find2 + 13)
    $Split = Stringsplit($readinhalt, @CRLF)
    $Columns = "Datum,UHRZEIT"
    For $k = 1 To $Split[0]
    If $Split[$k] = "" THen ContinueLoop
    $tmpsplit = Stringsplit($Split[$k], " = ", 1)
    $Columns &= ","&$tmpsplit[1]
    Next
    $txt = 'Begin Transaction ;' & @CRLF
    $txt &="INSERT INTO Daten ("&$Columns&") VALUES ('"&$Date&"','"&$Uhrzeit&"'"
    For $k = 1 To $Split[0]
    If $Split[$k] = "" THen ContinueLoop
    $tmpsplit = Stringsplit($Split[$k], " = ", 1)
    $txt &= ", '"&$tmpsplit[2]&"'"
    Next
    $txt &= ");"&@CRLF
    $txt &= 'Commit Transaction ;' & @CRLF
    _SQLite_Exec(-1, $txt)
    _SQLite_Exec(-1, "DELETE FROM Daten WHERE AgentCount = '0';")
    Else
    ContinueLoop
    EndIf

    [/autoit]

    Wie ihr seht arbeite ich im moment mit

    [autoit]

    StringInStr($read, "Trennstring", 0, $i)

    [/autoit]


    Damit wird immer wieder die gesamte Datei durchsucht, bis zum x-ten Vorkommen des Trennstrings.
    Jetzt hatte ich überlegt, ob ich nicht vom Beginn der Datei bis zu $findlast, also dem letzten Zeichen das ich brauche, alles lösche und dann von vorne beginne. Damit sollte dann ja die Laufzeit kürzer werden, da der String kleiner ist (richtig?)

    Ich denke ich muss mit FileSetPos arbeiten, weiß aber nicht, wie ich dann etwas lösche, überschreiben steht ja in der Hilfe.

    Weiß jemand wie das funktionieren könnte oder hat eine bessere Idee?

    Das Programm an sich funktioniert, es dauert nur fast 10 Minuten pro Datei und das ist mir eindeutig zu langsam :)

  • Mhh,

    eine Möglichkeit wäre das Logfile Zeile für Zeile abzuarbeiten - allerdings wird das Zeilenweise einlesen warscheinlich nicht so effektiv sein - andererseits könnte es die 10 Minuten doch locker schlagen

    Also nicht alles einlesen und nacheinander nach den Schlüsselwörtern durchsuchen sondern
    Zeile einlesen, auf Schlüsselwörter prüfen, nächste Zeile.

    Eine Methode dazwischen: Du liesst das Logfile in ein Array ein - ich hatte gerade mal gesucht aber nicht die Limits für ein Array gefunden.
    Ein Test mit einem Array mit 500.000 Zeilen ergab mit einer Prüfung und Textausgabe auf meinen Rechner einer Laufzeit von 50 Sekunden - ohne das Einlesen.

    Ich muss jetzt noch weg - ich würde sonst nacher mal einen Testkandidaten schreiben (der mir die daten erzeugt und wieder einliest), aber das sieht für mich schneller aus wenn du die Art der Prüfung umkehrst.

    BLinz

  • StringInStr kennt einen Parameter namens "start". Den hast du doch schon ein paar Mal eingesett. Warum nicht auch an dieser Stelle ;)

  • Also,

    ich hab mir einen kleinen Testkanditaten gebaut der erst eine Datei mit 500.000 Zeilen anlegt,
    diese dann Zeile für Zeile einliest, ggf. einen String ersetzt und in eine zweite Datei schreibt:

    Meine Zeiten:
    Datei anlegen in 4 Sekunden
    Datei einlesen, ändern, in 2. Datei schreiben: 14 Sekunden

    und mein Rechner ist jetzt nicht so schnell / neu. Das ganze direkt im Editor unkompiliert (falls das was ausmacht)

    Hier mein Testprogramm:

    Spoiler anzeigen
    [autoit]


    #Include <Array.au3>
    Dim $arrayTexte[5] = ["Meine Statistic blablablabla blablabla blablablabla blablablabla blablablabla blablablabla blablablabla", _
    "Meine RunningTime asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag", _
    "nur so ein Text asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag", _
    "noch ein weiterer Text asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag", _
    "Und eine weitere langweilige Zeile asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag asgdkagdkhsag"]

    [/autoit] [autoit][/autoit] [autoit]

    Dim $hDatei, $hNocheineDatei
    Dim $Timer, $i, $sTemp
    Dim $arrayDatei[1]

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;Datei anlegen

    [/autoit] [autoit][/autoit] [autoit]

    $hDatei = FileOpen("test.log",2)
    MsgBox(1,"Datei anlegen","Lege test.log mit 500.000 Zeilen an")
    $Timer = "Startzeit: " & @HOUR & ":" & @MIN & ":" & @SEC & @CRLF
    For $i = 1 To 500000 Step 1
    FileWriteLine($hDatei,$arrayTexte[Random(0,4,1)])
    Next
    FileClose($hDatei)
    $Timer = $Timer & "Stopzeit: " & @HOUR & ":" & @MIN & ":" & @SEC
    MsgBox(1,"Zeit für Datei anlegen:",$Timer)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;Datei in Array einlesen
    $arrayDatei[0] = 0
    $i = 0
    $hDatei = FileOpen("test.log",0)
    $hNocheineDatei = FileOpen("ausgabe.log",2)
    MsgBox(1,"Datei einlesen","Lese test.log mit 500.000 Zeilen ein")
    $Timer = "Startzeit: " & @HOUR & ":" & @MIN & ":" & @SEC & @CRLF
    While 1 > 0
    $sTemp = FileReadLine($hDatei)
    If @error = -1 Then
    $Timer = $Timer & "Stopzeit: " & @HOUR & ":" & @MIN & ":" & @SEC
    MsgBox(1,"Zeit für Datei einlesen:",$Timer)
    FileClose($hDatei)
    FileClose($hNocheineDatei)
    ExitLoop
    Else
    ;_ArrayAdd($arrayDatei,$sTemp)
    $i = $i + 1
    ;$arrayDatei[0] = $arrayDatei[0] + 1
    If StringInStr($sTemp,"RunningTime") > 0 Then
    ;ConsoleWrite(@HOUR & ":" & @MIN & ":" & @SEC & "---" & $i & "RunningTime" & @CRLF)
    StringReplace($sTemp,"RunningTime","Das ist viel viel besser")
    FileWriteLine($hNocheineDatei,$sTemp)
    Else
    ;ConsoleWrite(@HOUR & ":" & @MIN & ":" & @SEC & "---" & $i & @CRLF)
    EndIf
    EndIf
    WEnd

    [/autoit]

    Achja, Nachtrag:

    Vergiss das mit den Arrays - ich habe einen Test mit _ArrayAdd gemacht (sieht im Quelltext) und nach ein paar Minuten abgebrochen .... dauert zu lange oder falsche Methode