![]() |
Re: Eindeutiger Vergleich für große Dateien gesucht
genau den beitrag hatte ich mal vor ner zeit inhaliert. und dann eine große mmf klasse geschrieben.
die allerdings DB like funktioniert und nicht byte für byte |
Re: Eindeutiger Vergleich für große Dateien gesucht
@negah: Ich hab auch mal versucht Deinen Code umzusetzen... leider kommt es beim Vergleich hin und wieder zu Fehlern...
Delphi-Quellcode:
Result := False;
FileHandle1 := FileOpen(FileName1, fmOpenRead or fmShareDenyWrite); if FileHandle1 <> INVALID_HANDLE_VALUE then try FileHandle2 := FileOpen(FileName2, fmOpenRead or fmShareDenyWrite); if FileHandle2 <> INVALID_HANDLE_VALUE then try FileSize := GetFileSize(FileHandle1, nil); if FileSize = GetFileSize(FileHandle2, nil) then begin Result := True; if FileSize > 0 then begin MapHandle1 := CreateFileMapping(FileHandle1, nil, PAGE_READONLY, 0, 0, nil); if MapHandle1 <> INVALID_HANDLE_VALUE then try MapHandle2 := CreateFileMapping(FileHandle2, nil, PAGE_READONLY, 0, 0, nil); if MapHandle2 <> INVALID_HANDLE_VALUE then try CurSize := FileSize mod AllocGran; if CurSize = 0 then CurSize := AllocGran; CurPos := FileSize - CurSize; repeat CurPosHi := CurPos div 4294967296; CurPosLo := CurPos mod 4294967296; P1 := MapViewOfFile(MapHandle1, FILE_MAP_READ, CurPosHi, CurPosLo, CurSize); if P1 <> nil then try P2 := MapViewOfFile(MapHandle2, FILE_MAP_READ, CurPosHi, CurPosLo, CurSize); if P2 <> nil then try Result := CompareMem(P1, P2, CurSize); finally UnmapViewOfFile(P2); end else RaiseLastWin32Error; finally UnmapViewOfFile(P1); end else RaiseLastWin32Error; CurPos := CurPos - CurSize; CurSize := AllocGran; until (CurPos < 0) or not Result; finally CloseHandle(MapHandle2); end else RaiseLastWin32Error; finally CloseHandle(MapHandle1); end else RaiseLastWin32Error; // <------------ Hier wird der Fehler angezeigt // MapHandle1 ist also INVALID_HANDLE_VALUE // Warum? end; end; finally FileClose(FileHandle2); end else RaiseLastWin32Error; finally FileClose(FileHandle1); end else RaiseLastWin32Error; |
Re: Eindeutiger Vergleich für große Dateien gesucht
keine Ahnung ?!
hast du mal gecheckt iff AnsiCompareText(FileName1, FileName2) <> 0 !!! eventuell kann es also sein das beide oder eine der Dateien schon geöffnet wurde und du keinen Zugriff mit deinem Zugriffsflags bekommst. fmShareDenyWrite könnte das Problem sein falls ein anderer Process die Datei mit Vollzugriff oder sogar exklusiv geöffnet hat. Dann treten Fehler NICHT sofort mit FileOpen(), GetFileSize() etc. pp. auf sondern erst wenn man Daten aus der Datei lesen möchte. Dieser Fehler kann dir aber mit jeder Methode zu jeder Zeit auftreten, das OS und die anderen Anwendungen möchte halt auch ihre Daten speichern ;) Gruß Hagen PS: als Entschuldigung für denMist muß ich auch sagen das der obige Source von mir niemals getestet wurde, nochnichtmal das er auf meinem Rechner jemals das Licht eines Compilers gesehen hätte ;) ich habe ihn hier live programmiert. |
Re: Eindeutiger Vergleich für große Dateien gesucht
:oops: da hatte ich doch gerade den "falschen" Fehler markiert...
Viel häufiger tritt jedoch an folgender Stelle ein Fehler auf:
Delphi-Quellcode:
...
P1 := MapViewOfFile(MapHandle1, FILE_MAP_READ, CurPosHi,
CurPosLo, CurSize); Zitat:
|
Re: Eindeutiger Vergleich für große Dateien gesucht
@frifra, @negaH:
genau den selben fehler erhalte ich ja auch. ich hab mich schon gewundert warum du einen anderen bekommst. ich habe gestern noch einiges zu dem thema gelesen, und es muss wohl wirklich an CurPosHi u. CurPosLo liegen. Irgendwie werden die falsch geteilt, bzw. der rest ist nicht mit "dwAllocationGranularity" kompatibel. ich weiß aber momentan auch nicht wirklich warum. |
Re: Eindeutiger Vergleich für große Dateien gesucht
Jaja, wenn man einfach stupid irgendwas abtippt das ein Fachidiot ohne eigene Tests gepostet hat ;)
Beachtet bitte die beiden Zeilen die mit 1.) und 2.) makiert wurden.
Delphi-Quellcode:
So. Bei meinen Test ist CompareFile() ca. 140% schneller als CompareFile1().
function GetFileSizeInt64(const FileName: String): Int64;
var Handle: THandle; Data: WIN32_FIND_DATA; begin Result := -1; Handle := FindFirstFile(Pointer(FileName), Data); if Handle <> INVALID_HANDLE_VALUE then try Int64Rec(Result).Hi := Data.nFileSizeHigh; Int64Rec(Result).Lo := Data.nFileSizeLow; finally Windows.FindClose(Handle); end; end; function GetSystemAllocationGranularity: DWord; var Info: TSystemInfo; begin GetSystemInfo(Info); Result := Info.dwAllocationGranularity; end; function CompareFile(const FileName1, FileName2: String): Boolean; procedure DoError; begin RaiseLastWin32Error; // auskommentieren falls keine Exceptions erwünscht // Result := False; end; var AllocSize: DWord; CurSize: DWord; CurPos: Int64; FileHandle1, FileHandle2: THandle; MapHandle1, MapHandle2: THandle; FileSize1, FileSize2: Int64; View1, View2: Pointer; begin Result := AnsiCompareText(FileName1, FileName2) = 0; if Result then Exit; FileSize1 := GetFileSizeInt64(FileName1); FileSize2 := GetFileSizeInt64(FileName2); if FileSize1 or FileSize2 >= 0 then begin Result := FileSize1 = FileSize2; if not Result or (FileSize1 = 0) then Exit; AllocSize := GetSystemAllocationGranularity * 8; Assert(AllocSize < MaxInt); // CompareMem() Size Param is Integer FileHandle1 := CreateFile(Pointer(FileName1), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); if FileHandle1 <> INVALID_HANDLE_VALUE then try FileHandle2 := CreateFile(Pointer(FileName2), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); if FileHandle2 <> INVALID_HANDLE_VALUE then try MapHandle1 := CreateFileMapping(FileHandle1, nil, PAGE_READONLY, 0, 0, nil); if MapHandle1 <> INVALID_HANDLE_VALUE then try MapHandle2 := CreateFileMapping(FileHandle2, nil, PAGE_READONLY, 0, 0, nil); if MapHandle2 <> INVALID_HANDLE_VALUE then try CurSize := FileSize1 mod AllocSize; if CurSize = 0 then CurSize := AllocSize; CurPos := FileSize1 - CurSize; repeat Assert(CurPos >= 0); Assert(CurPos mod AllocSize = 0); View1 := MapViewOfFile(MapHandle1, FILE_MAP_READ, Int64Rec(CurPos).Hi, Int64Rec(CurPos).Lo, CurSize); if View1 <> nil then try View2 := MapViewOfFile(MapHandle2, FILE_MAP_READ, Int64Rec(CurPos).Hi, Int64Rec(CurPos).Lo, CurSize); if View2 <> nil then try Result := CompareMem(View1, View2, CurSize); finally UnmapViewOfFile(View2); end else DoError; finally UnmapViewOfFile(View1); end else DoError; CurSize := AllocSize; // 1.) CurPos := CurPos - CurSize; // 2.) until not Result or (CurPos < 0); finally CloseHandle(MapHandle2); end else DoError; finally CloseHandle(MapHandle1); end else DoError; finally CloseHandle(FileHandle2); end else DoError; finally CloseHandle(FileHandle1); end else DoError; end else DoError; end; function CompareFile1(const FileName1, FileName2: String): Boolean; procedure DoError; begin RaiseLastWin32Error; // Result := False; end; const BufferSize = 65535; var FileSize1,FileSize2: Int64; CurSize: Integer; Stream1,Stream2: TStream; Buffer1,Buffer2: array of Byte; begin Result := AnsiCompareText(FileName1, FileName2) = 0; if Result then Exit; FileSize1 := GetFileSizeInt64(FileName1); FileSize2 := GetFileSizeInt64(FileName2); if FileSize1 or FileSize2 >=0 then begin Result := FileSize1 = FileSize2; if not Result or (FileSize1 = 0) then Exit; Stream1 := TFileStream.Create(FileName1, fmOpenRead or fmShareDenyWrite); try Stream2 := TFileStream.Create(FileName2, fmOpenRead or fmShareDenyWrite); try SetLength(Buffer1, BufferSize); SetLength(Buffer2, BufferSize); while Result and (FileSize1 > 0) do begin CurSize := BufferSize; if CurSize > FileSize1 then CurSize := FileSize1; Stream1.Read(Buffer1[0], CurSize); Stream2.Read(Buffer2[0], CurSize); Result := CompareMem(@Buffer1[0], @Buffer2[0], CurSize); FileSize1 := FileSize1 - CurSize; end; finally Stream2.Free; end; finally Stream1.Free; end; end else DoError; end; Aber am wichtigsten dürfter der Fakt sein das CompareFile() umso schneller arbeitet um so öfters eine Datei als MMF in den Speicher geladen wurde, sprich schon im Cache ist. Das ist gut so denn ich nehme an das zumindestens eine der beiden Dateien kurz vorher, ebenfalls per MMF, gehasht wurde. D.h. sie ist schon im Speicher weil man ja noch den Hash per MD4 vorher ziehen wird. Die andere Datei stellt ja die Referenz die schon in der Datenbank gespeichert wurde,also auch deren Hash Wert. Somit dürften die MMF's tatsächlich einiges an Speed bringen. Gruß Hagen |
Re: Eindeutiger Vergleich für große Dateien gesucht
Wenn man es aber genauer betrachtet so sind 140% zu wenig falls man mit Hashs arbeiten wird. Die Wahrscheinlichkeit das nach einer MD4 Hash Überprüfung die Funktion CompareFile() aufgerufen werden muß ist einfach viel zu gering um nicht mit den VCL-Streams zu arbeiten, besondersim Hinblick auf die negativen Seiteneffekte der MMF's wie beim Borland Link oben beschrieben. (kannte ich selber noch nicht)
Bei einer MD4 Hash Überprüfung hat man ja zumindestens schonmal einen Hashwert einer der beiden Dateien in einer DB gespeichert. Die Erzeugung der MD4 Prüfsumme für die zweite Datei muß ja nur diese zweite Datei öffnen und laden. Das verringert schonmal um 200% den nötigen Aufwand. Gruß Hagen |
Re: Eindeutiger Vergleich für große Dateien gesucht
Liste der Anhänge anzeigen (Anzahl: 1)
So nachfolgend noch ein Code um einen MD4 über eine Datei zu ziehen.
Dieses mal sieht die Performance schon anders aus. Es gibt in fact keinen Unterschied mehr zwischen MMF's und normalen Streams, also sollten Streams benutzt werden. Allerdings unterscheidet sich die Laufzeit zwischen MD4HashFile1() und CompareFile() enorm. Mit meinen 160Mb großen Testdateien, die noch NICHT im Cache lagen, sieht es nun so aus: CompareFile1() benötigt 55 Sekunden. HashFile1() benötigt 10 Sekunden. Was lernen wir daraus ? Das ein zweimaliger Aufruf von HashFile1() ca. 20 Sekunden benötigt und somit mehr als doppelt so schnell ist wie nur ein Aufruf von CompareFile1() !! Gruß Hagen PS: wer's in die CodeLib stellen will soll es selber tuen ;)
Delphi-Quellcode:
[edit=Sharky]Nach Rücksprache den gesamt Code als Datei angehängt. Mfg, Sharky[/edit]
type
PMD4Digest = ^TMD4Digest; TMD4Digest = array[0..3] of Cardinal; PMD4Buffer = ^TMD4Buffer; TMD4Buffer = array[0..15] of Cardinal; // // Rest im Anhang des Postings // |
Re: Eindeutiger Vergleich für große Dateien gesucht
Liste der Anhänge anzeigen (Anzahl: 1)
@negaH:
ich habe die korrigierte fassung der comparefile prozedur (also mmf) über das selbe verzeichnis laufen lassen. ich dachte zwar schon, das programm hätte sich aufgehängt, aber nach 1391 sekunden war er dann doch noch erfolgreich fertig. jaja, die 0,2 sek. wären auch zu schön um wahr zu sein. trotzdem vielen dank für die mühe u. arbeit die du dir hier gemacht hast. Zitat:
|
Re: Eindeutiger Vergleich für große Dateien gesucht
@hagen:
die asm-prozedur sieht lustig aus :) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:33 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz