Dateiinhalte vergleichen

  • Ich weiß dieses Thema gab es schon desöfteren und ich hab auch schon über die Suche einige gefunden.
    Das Script lief zwar vorher schon, bevor ich angefangen hab zu suchen, aber es war recht langsam.

    Worum gehts: Das Script soll 2 Dateien miteinander vergleichen und Unterschiede in Datei 3 schreiben.

    Dabei müssen verschiedene Dinge beachtet werden.
    Es werden je 2 Werte aus der jeweiligen Datei gelesen; Pfad + Wert.
    Diese Werte soll er mit einer neueren Version der Datei vergleichen.
    Die Crux dabei ist nun, dass die Reihenfolge unterschiedlich sein kann.

    Das bedeutet nun genau:

    • Pfad + Wert aus Datei 1 lesen
    • Pfad in Datei 2 suchen

      • wenn gefunden, dann Werte vergleichen

        • wenn unterschiedlich, dann in Datei 3 schreiben (sonst nichts)
        • wenn gleich, dann nichts machen, sondern wieder zum Anfang springen (nächtsen Pfad + Wert aus Datei 1 lesen)
      • wenn nicht gefunden, dann in Datei 3 schreiben

    Der Aufbau beider Dateien ist identisch, hier mal ein Auszug:

    Code
    7e2f19c75105047a0668b19ee620dcac *ace/ace_cp.deploy
    cf4684fe0d4b39cb8edccf6ea4922e8d *ace/CM/bkg.png
    e2d0b78edeafd93685b73733877aca10 *ace/CM/cmerrors.ace
    fbe2f82503b07029d469959f2324425f *ace/CM/mdinfo.ace


    Mein Script:

    Spoiler anzeigen
    [autoit]

    #include <File.au3>

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

    Global $OldFile = "old.txt", $NewFile = "new.txt", $TargetLog = @ScriptDir & "\changes.txt"
    Global $OldHandle, $NewHandle, $TargetHandle, $ChangeAmount, $OldLines, $NewLines, $OldCounter = 4, $NewCounter = 4, $OldData, $NewData

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

    _FileCreate($TargetLog)
    $OldHandle = FileOpen($OldFile, 0) ; current state file
    $NewHandle = FileOpen($NewFile, 0) ; new state file
    $TargetHandle = FileOpen($TargetLog, 2) ; difference file

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

    _compareFiles()

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

    ;~ ProgressOn("test", "file")

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

    Func _compareFiles()

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

    $OldLines = _FileCountLines($OldFile)
    $NewLines = _FileCountLines($NewFile)

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

    While $OldCounter <= $OldLines
    $OldData = StringSplit(FileReadLine($OldHandle, $OldCounter), "*")
    $OldData[1] = StringTrimRight($OldData[1], 1)
    ;~ ProgressSet($OldCounter, $OldData[2])
    _searchFile()

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

    $OldCounter += 1
    WEnd
    Exit
    EndFunc

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

    Func _searchFile()
    Local $match = 0

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

    While $NewCounter <= $NewLines
    $NewData = StringSplit(FileReadLine($NewHandle, $NewCounter), "*")
    $NewData[1] = StringTrimRight($NewData[1], 1)

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

    If $NewData[2] = $OldData[2] Then
    $match = 1
    Select
    Case $OldData[1] = $NewData[1]

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

    Case $OldData[1] <> $NewData[1]
    FileWrite($TargetHandle, $NewData[2] & @CRLF)
    ExitLoop
    EndSelect
    Else
    $NewCounter += 1
    EndIf

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

    If $match = 0 And $NewCounter = $NewLines Then FileWrite($TargetHandle, $NewData[2] & @CRLF)
    WEnd
    EndFunc

    [/autoit]

    Das funktioniert soweit auch, aber es scheint extrem langsam zu sein (das Script beendet sich selbst nach 10 Minuten nicht von selbst).
    Nach 2 Minuten hat es gerade mal 2 Unterschiede gefunden (von Einträgen die unter den ersten 10 Zeilen sind).

    Als generelle Info: Die Anzahl der Zeilen beider Dateien ist >3000.
    Dennoch sollte es daran nicht liegen, da die CPU nicht mal 2% Auslastung hat...


    Jemand Vorschläge zur Verbesserung? Hab ich vielleicht unnötige Dinge drin?

    Grüße

    3 Mal editiert, zuletzt von Matricus (26. März 2012 um 08:10)

  • Fehler selbst gefunden *Kopf->Wand*.
    Fehl war, dass er sich in einer Endlosschleife gedreht hat.

    Bei der Überprüfung der Werte habe ich vergessen "ExitLoop" einzufügen, sofern beide Werte gleich sind (und er damit zum nächsten Pfad gehen soll).

    /closed

  • Würde da mit _FileReadToArray arbeiten, da du dadurch nicht ständig auf die Datei und somit HDD zugreifen musst.

    1. Datei 1 in ein Array1 einlesen
    2. Datei 2 in Array2 einlesen
    3. while schleife die jeden eintrag von array1 per strinsplit mit delimiter " " (Leerzeichen) in array1b schreibt
    ---> in Array 1b sollten nun nur noch die pfade stehen, also "*ace....."
    4. while schleife die _arraysearch ausführt und in array2 nach den pfaden aus allen einträgen von array 1b sucht
    4a wird eine übereinstimmung gefunden vergleichen wir array2[trefferindex] mit array1[zählerindex der suchschleife]
    4b weichen Inhalte ab, dann schreibt man array2[trefferindex] in Datei 3 oder was besser wäre in ein Array3 und ganz am ende also nach der suchschleife mit _FileWriteFromArray in Datei3
    5. Ferig?

    Sorry war zu faul das in Programmcode zu verpacken, aber so in der Art sollte das recht flott gehn.

  • &quot;in etwa so - ungetestet&quot;
    [autoit]

    #include <array.au3>
    #include <File.au3>

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

    $File3 = "test3.txt"
    $aFile1 = _ReadToArray("test.txt")
    $aFile2 = _ReadToArray("test2.txt")

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

    For $i = 1 To UBound($aFile1) - 1
    $index = _ArraySearch($aFile2, $aFile1[$i][0], 0, 0, 1, 0, 1)
    If Not @error Then
    If $aFile1[$i][1] <> $aFile2[$index][1] Then
    FileWriteLine($File3, $aFile1[$i][0] & " " & $aFile1[$i][1])
    EndIf
    ElseIf @error = 6 Then
    FileWriteLine($File3, $aFile1[$i][0] & " " & $aFile1[$i][1])
    EndIf
    Next

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

    Func _ReadToArray($File)
    Local $a2d[1][2], $aFile
    _FileReadToArray($File, $aFile)
    For $i = 1 To $aFile[0]
    _Array2DAdd($a2d, StringReplace($aFile[$i], " ", "|", 1))
    Next
    Return $a2d
    EndFunc ;==>_ReadToArray

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

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;
    ; Function _Array2DAdd(ByRef $avArray, $sValue='')
    ;
    ; Description Redim Array Size and add an Array element at last position
    ; Works with any occurences in 2nd Dimension
    ; Works also with 1D-Array
    ;
    ; Parameter $avArray Given Array
    ; optional $sValue Value of new Element, parts must be seperate with '|'
    ;
    ; Return Succes -1
    ; Failure 0 and set @error
    ; @error = 1 given array is not array
    ; @error = 2 given parts of Element too less/much
    ;
    ; Author BugFix ([email='bugfix@autoit.de'][/email])
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    Func _Array2DAdd(ByRef $avArray, $sValue = '')
    If (Not IsArray($avArray)) Then
    SetError(1)
    Return 0
    EndIf
    Local $UBound2nd = UBound($avArray, 2)
    If @error = 2 Then
    ReDim $avArray[UBound($avArray) + 1]
    $avArray[UBound($avArray) - 1] = $sValue
    Else
    Local $arValue
    ReDim $avArray[UBound($avArray) + 1][$UBound2nd]
    If $sValue = '' Then
    For $i = 0 To $UBound2nd - 2
    $sValue &= '|'
    Next
    EndIf
    $arValue = StringSplit($sValue, '|')
    If $arValue[0] <> $UBound2nd Then
    SetError(2)
    Return 0
    EndIf
    For $i = 0 To $UBound2nd - 1
    $avArray[UBound($avArray) - 1][$i] = $arValue[$i + 1]
    Next
    EndIf
    Return -1
    EndFunc ;==>_Array2DAdd

    [/autoit]

    edit: Ich les grad, du schreibst da zwar

    Zitat

    1. Pfad + Wert aus Datei 1 lesen

    Scheint aber eher andersrum in deiner Datei zu stehen. In dem Fall müssten die Werte für die Dimensionen im _ArraySearch() verändert werden.

    Spoiler anzeigen
    [autoit]


    For $i = 1 To UBound($aFile1) - 1
    $index = _ArraySearch($aFile2, $aFile1[$i][1], 0, 0, 1, 0, 1)
    If Not @error Then
    If $aFile1[$i][0] <> $aFile2[$index][0] Then
    FileWriteLine($File3, $aFile1[$i][0] & " " & $aFile1[$i][1])
    EndIf
    ElseIf @error = 6 Then
    FileWriteLine($File3, $aFile1[$i][0] & " " & $aFile1[$i][1])
    EndIf
    Next

    [/autoit]