Delphi-PRAXiS
Seite 12 von 12   « Erste     2101112   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Eindeutiger Vergleich für große Dateien gesucht (https://www.delphipraxis.net/50896-eindeutiger-vergleich-fuer-grosse-dateien-gesucht.html)

himitsu 6. Aug 2005 19:37

Re: Eindeutiger Vergleich für große Dateien gesucht
 
Hab zwar den Code zum Dateivergleich noch nicht gefunden, aber ein Stringvergleich tut es doch auch.
Der Dateivergleich entsprach aber in etwa dem Inhalt der "If Length(S2) > 1 Then"-Bedingung.
(hauptsächlich Vergleich der Hash's und bei gleichem Hash nochmal einen byteweisen Vergleich der Daten,
damit das Problem gleicher Hash's, trotz unterschiedlicher Rohdaten nicht auftritt)

"S2 = Wortliste..." führt eine Funktion aus, welche die Bytes vergleicht und beim ersten Unterschied den Vergleich abbricht,
also die gesammten Stringdaten werden fast niemals verglichen/bearbeitet.

Und wenn man jetzt mal die beiden Varianten misst, dann wird eine erhebliche Steigerung der Geschwindigkeit dankt der Hash's auffallen.

Ein Vergleich ohne Hash's ist halt nur dann schneller, wenn nur ein einziger String, oder eben eine einzige Datei mit einem anderen String / einer anderen Datei verglichen wird.
Aber wenn man mehrere Strings/Dateien untereinander vergleicht, sieht das ganz anders aus, da ja sonst jeder String / jede Datei mehrfach eingelesen wird ... beim Hash hat mann dagegen einen netten kleinen Wert zum Vergleich ganz schnell zur Hand.

Warum hier unter Umständen nochmals die Strings/Dateien direkt miteinander Verglichen wird,
brauch ich dank Nico/Hagen ja nichtnochmal zu erklären.
z.B.
Zitat:

Wenn die Prüfsummen gleich sind, müssen die Daten nicht identisch sein.

Input: S
z.B. Inhalt einer TextDatei

Output: Wortliste
Liste aller enthaltenen Wörter
bestehend aus 0-9, A-Z, "_" und a-z


Delphi-Quellcode:
Var S, S2: AnsiString;
  i, i2, i3, L: Integer;
  H: LongWord;
  Wortliste: Array of Record
    Hash: LongWord;
    Wort: AnsiString;
  End;

Begin
  Wortliste := nil;
  L := Length(S);
  While (i <= L) and not (S[i] in ['0'..'9', 'A'..'Z', '_', 'a'..'z']) do Inc(i);
  While i <= L do Begin
    i2 := i;
    While (i2 <= L) and (S[i2] in ['0'..'9', 'A'..'Z', '_', 'a'..'z']) do Inc(i2);
    S2 := Copy(S, i, i2 - i);
    i := i2;
    If Length(S2) > 1 Then Begin
      H := CRC32(S2);
      i3 := -1;
      For i2 := High(Wortliste) downto 0 do
        If (H = Wortliste[i2].Hash) and (S2 = Wortliste[i2].Wort) Then Begin
          i3 := i2;
          Break;
        End;
      If i3 < 0 Then Begin
        i3 := Length(Wortliste);
        SetLength(Wortliste, i3 + 1);
        Wortliste[i3].Hash     := H;
        Wortliste[i3].Wort     := S2;
      End;
    End;
    While (i <= L) and not (S[i] in ['0'..'9', 'A'..'Z', '_', 'a'..'z']) do Inc(i);
  End;
End;

Delphi-Quellcode:
Var S, S2: AnsiString;
  i, i2, i3, L: Integer;
  Wortliste: Array of AnsiString;

Begin
  Wortliste := nil;
  L := Length(S);
  While (i <= L) and not (S[i] in ['0'..'9', 'A'..'Z', '_', 'a'..'z']) do Inc(i);
  While i <= L do Begin
    i2 := i;
    While (i2 <= L) and (S[i2] in ['0'..'9', 'A'..'Z', '_', 'a'..'z']) do Inc(i2);
    S2 := Copy(S, i, i2 - i);
    i := i2;
    If Length(S2) > 1 Then Begin
      i3 := -1;
      For i2 := High(Wortliste) downto 0 do
        If S2 = Wortliste[i2].Wort Then Begin
          i3 := i2;
          Break;
        End;
      If i3 < 0 Then Begin
        i3 := Length(Wortliste);
        SetLength(Wortliste, i3 + 1);
        Wortliste[i3] := S2;
      End;
    End;
    While (i <= L) and not (S[i] in ['0'..'9', 'A'..'Z', '_', 'a'..'z']) do Inc(i);
  End;
End;

In etwa so könnte es z.B. für Dateien aussehen:
Delphi-Quellcode:
List: Array of Record
  Hash: LongWord;
  FN: AnsiString;
End;


H := CRC32File(FileName);
i2 := -1;
For i := High(List) downto 0 do
  If (H = List[i].Hash) and CompareFile(FileName, List[i].FN) Then Begin
    i2 := i;
    Break;
  End;
If i2 < 0 Then Begin
  // Datei in die Liste eintragen
  i2 := Length(List);
  SetLength(List, i2 + 1);
  List[i2].Hash := H;
  List[i2].FN  := FileName;
End Else Begin
  // eine Datei mit dem selben Inhalt existiert bereits
End;

PS: wie Hagen schon sagte, kann man jetzt noch die Dateigöße mit in den Vergleich mit einbeziehen, um nochmeh Geschwindigkeit rauszubekommen.
Aber so wie mein DemoCode aufgebaut ist, ist dieses nicht wirklich nötig, da ein weiteres Vergleichskriterium die gesammte Prozedur natürlich erstmal etwas verlangsamt
und die erhoffte Beschleunigung nur dann eintreten wird, wenn die Hash's gleich sind ... was ja auch nicht gerade oft vorkommt.
Ergo ist ein weiteres Vergleichskriterium, wie Größe/Datum... hierfür unnötig.
Aber wie gesagt, wenn man wiederum nur eine Datei mit einer anderen Vergleichen will, können witere Kriterien Wunder bewirken ;)

PSS: was ich noch sagen bezöglich der maximalen Dateigröße sagen wollte ...
Viele Dateifunktionen arbeiten nur mit 32 Bit ... und obwohl die netten WinAPI-Funktionen auch 64 Bit verstehen können, wird dennoch (meistens) nur mit 32 Bit gearbeitet.
Also versagen die meisten Hashfunktionen schon bei Dateien über 2 GB.
Die Hashfunktionen mögen ja auch mit mehr als 2 GB umgehen können, aber wenn der Dateiinput dort aufgibt, bringt dieses nun auch nichts.

Und da die Dateien/Datenträger immer größer werden, sind mehr als 2 GB nichts exotisches mehr,
also hab ich meine UCC und demnach dir darin enthaltenen Hashfunktionen natürlich mit 64-Bit ausgestattet.


PS: Ja, das mit dem unverschämten Kopieren ist nicht nett und ich kann sowar ja auch nicht leiden.
Ich bin allerdings der Meinung, das es dabei nicht auf bestimmte Regionen ankommt, wie die Programmierer dort damit umgehen.

In meinem UCC habe ich zwar das Meißte selbst erstellt und an den entsprechenden Stellen, wo es nicht volltändig aus meiner Feder stammt, wird dieses dann auch erwähnt.




[add]
och menno ... immer dieser Hagen mit seinen Geheimnissen ... da denkt man mal, man hat 'nen Fehler in seinen Codes gefunden und dann behauptet der doch tatsächlich, das es angeblich richtig so sei :(
und wenn man dann die vielen Beiträge dort oben nochmal durchsieht, dann fällt einem auf, daß man sich die Arbeit mit den Codes auch hätte sparen können, weil einiges davon schonmal gesagt wurde :wall:

Ich muß unbedingt mal wieder etwas mehr Zeit hier verbringen ... denn bei solchen Themen fällt es doch stark auf, wenn man nicht ständig hier ist ... man kommt einfach nicht mehr hinterher -.-''

so, noch 2 Datei übrig

MuTzE.Y85 9. Mai 2014 15:42

AW: Eindeutiger Vergleich für große Dateien gesucht
 
Mahlzeit,

der Thread ist schon sehr alt, aber ich habe da trotzdem mal eine Frage :-D
Ich nutze die FileCompare.pas von negaH (Hagen) um 2 Verzeichnisse (A und B) zu Vergleichen, also Datei für Datei.

Dabei nutze ich diese Funktion
Code:
function CompareFile(const FileName1, FileName2: String): Boolean; overload;
begin
  Result := (AnsiCompareText(FileName1, FileName2) = 0) or
            ((GetFileSize(FileName1) = GetFileSize(FileName2)) and
             (HashFile(FileName1) = HashFile(FileName2)) and
             CompareFilePhysical(FileName1, FileName2));
end;
Anschließend werden die unterschiedlichen Dateien synchronisiert (Von A nach B).
Lasse ich nun die Funktion nochmal drüber laufen, findet er wieder Unterschiede (sogar andere Dateien wie vorher), obwohl ich nichts verändert habe.
Nehme ich aber aus der Funktion oben den Teil mit der MD4-Überprüfung raus (HashFile), funktioniert es.

Ist da vielleicht ein Fehler drin :?:

p80286 9. Mai 2014 16:18

AW: Eindeutiger Vergleich für große Dateien gesucht
 
Zitat:

Zitat von MuTzE.Y85 (Beitrag 1258448)
Ich nutze die FileCompare.pas von negaH (Hagen) um 2 Verzeichnisse (A und B) zu Vergleichen, also Datei für Datei.
...
Ist da vielleicht ein Fehler drin :?:

Die Wahrscheinlichkeit ist eher gering. U.u hast Du eine Kleinigkeit geändert, die sich so auswirkt?
Ich habe mir nicht den ganzen Thread durchgelesen, aber wenn ich es richtig behalten habe geht Hagen von einer bestimmten "üblichen" Konstellation aus.
Ich würde so arbeiten
Code:
if filesize(file1)=filesize(2) then
  if hash(file1)=hash(file2) then
    if binary(file1)=binary(file2) then FileIsEqual
Das AnsiCompareText hat mir nichts gebracht, aber das kann natürlich auch an den Dateiinhalten liegen.

Ändern sich die Inhalte einer Datei nicht, ändert sich auch der Hash-Wert nicht. Falls doch ist da etwas faul. U.U. solltest Du da mal ein Vergleichsprotokoll mitlaufen lassen um zu sehen mit welchen Daten Du da hantierst.

Gruß
K-H

Sir Rufo 9. Mai 2014 16:22

AW: Eindeutiger Vergleich für große Dateien gesucht
 
Das AnsiCompare ist ja nur für den Fall, dass man beides Mal den gleichen Dateinamen angibt.
Die sind definitiv gleich, weil diesselbe ;)

p80286 9. Mai 2014 16:27

AW: Eindeutiger Vergleich für große Dateien gesucht
 
:oops: Das kommt davon wenn man nicht richtig liest, Jahre her und trotzdem aufgefallen:oops:

Gruß
K-H

MuTzE.Y85 9. Mai 2014 23:21

AW: Eindeutiger Vergleich für große Dateien gesucht
 
Zitat:

Zitat von p80286 (Beitrag 1258456)
Ich würde so arbeiten
Code:
if filesize(file1)=filesize(2) then
  if hash(file1)=hash(file2) then
    if binary(file1)=binary(file2) then FileIsEqual

Naja die oben genannte Funktion, die ich nutze ist ja aus der FileCompare.pas :wink:
Sie wurde also von Hagen dort hinein geschrieben.

Zitat:

Zitat von p80286 (Beitrag 1258456)
Die Wahrscheinlichkeit ist eher gering. U.u hast Du eine Kleinigkeit geändert, die sich so auswirkt?

Darum habe ich mich auch vorsichtig ausgedrückt :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:04 Uhr.
Seite 12 von 12   « Erste     2101112   

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz