Registriert seit: 16. Mai 2005
620 Beiträge
|
Re: Eindeutiger Vergleich für große Dateien gesucht
3. Aug 2005, 18:16
ok, hier ist der vergleich. ich weise aber darauf hin, dass die prozedur CompareFilesFileStream die daten von vorne nach hinten liest, während CompareFilesMemoryMapped von hinten nach vorne (s. negaH's post). das heisst die prozedur CompareFilesFileStream müsste dahingehend optimiert werden um einen einigermaßen adequaten vergleich zu erzielen.
zum vergleich:
daten die überprüft wurden: 22 dateien, gesamtgröße: 6.480.244.455 Bytes. dabei war die datei, auf die es ankommt (wwdofficialnltls7l1.exe, 1.438.201.380 Bytes) zweifach vorhanden, um zu testen ob sie als unterschiedlich oder gleich erkannt wird.
hier der verwendete code:
Delphi-Quellcode:
function CompareFilesFileStream(const File1, File2: String): Boolean;
const
BlockSize = 65536;
var
FSFile1, FSFile2: TFileStream;
L1, L2: Integer;
B1, B2: Array[1..BlockSize] of Byte;
begin
Result := False;
FSFile1 := TFileStream.Create(File1, fmOpenRead or fmShareDenyWrite);
try
FSFile2 := TFileStream.Create(File2, fmOpenRead or fmShareDenyWrite);
try
if FSFile1.Size = FSFile2.Size then
begin
while FSFile1.Position < FSFile1.Size do
begin
L1 := FSFile1.Read(B1[1], BlockSize);
L2 := FSFile2.Read(B2[1], BlockSize);
if L1 <> L2 then
Exit;
if not CompareMem(@B1[1], @B2[1], L1) then
Exit;
end;
Result := True;
end;
finally
FSFile2.Free;
end;
finally
FSFile1.Free;
end;
end;
Quelle
und hier die prozedur die mittlerweile entstanden ist.
Delphi-Quellcode:
function GetHugeFileSize(const Filename: String): Int64;
var
hFile: Longword;
Data: WIN32_FIND_DATA;
Size: LARGE_INTEGER;
begin
Result := -1;
hFile := FindFirstFile(PChar(Filename), Data);
try
if hFile <> INVALID_HANDLE_VALUE then
begin
Size.LowPart := Data.nFileSizeLow;
Size.HighPart := Data.nFileSizeHigh;
Result := Size.QuadPart;
end;
finally
Windows.FindClose(hFile);
end;
end;
function GetSystemAllocationGranularity: Cardinal;
var
PSysInfo: TSystemInfo;
begin
GetSystemInfo(PSysInfo);
Result := PSysInfo.dwAllocationGranularity;
end;
function CompareFilesMemoryMapped(const File1, File2: String; SysAllocSize: Cardinal): Boolean;
var
CurSize: DWord;
CurPos: Int64;
hFile1, hFile2: THandle;
hMap1, hMap2: THandle;
FileSize: Int64;
P1, P2: Pointer;
begin
Result := False;
hFile1 := CreateFile(@File1[1], GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if hFile1 <> INVALID_HANDLE_VALUE then
try
hFile2 := CreateFile(@File2[1], GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if hFile2 <> INVALID_HANDLE_VALUE then
try
FileSize := GetHugeFileSize(File1); //GetFileSizeInt64(hFile1);
if FileSize = GetHugeFileSize(File2) then //GetFileSizeInt64(hFile1) then
begin
Result := True;
if FileSize > 0 then
begin
hMap1 := CreateFileMapping(hFile1, nil, PAGE_READONLY, 0, 0, nil);
if hMap1 <> INVALID_HANDLE_VALUE then
try
hMap2 := CreateFileMapping(hFile2, nil, PAGE_READONLY, 0, 0, nil);
if hMap2 <> INVALID_HANDLE_VALUE then
try
CurSize := FileSize mod SysAllocSize;
if CurSize = 0 then
CurSize := SysAllocSize;
CurPos := FileSize - CurSize;
repeat
P1 := MapViewOfFile(hMap1, FILE_MAP_READ, Int64Rec(CurPos).Hi, Int64Rec(CurPos).Lo, CurSize);
if P1 <> nil then
try
P2 := MapViewOfFile(hMap2, FILE_MAP_READ, Int64Rec(CurPos).Hi, Int64Rec(CurPos).Lo, 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 := SysAllocSize;
until
(CurPos <= 0) or (not Result);
finally
CloseHandle(hMap2);
end; // else RaiseLastWin32Error;
finally
CloseHandle(hMap1);
end; // else RaiseLastWin32Error;
end;
end;
finally
CloseHandle(hFile2);
end; // else RaiseLastWin32Error;
finally
CloseHandle(hFile1);
end; // else RaiseLastWin32Error;
end;
ich hoffe, dass soweit alles fehlerfrei ist. am besten wäre natürlich, wenn du beide prozeduren selbst mal testest und mir eventuelle fehler nennst.
hinweis: ich habe während der beiden vergleiche noch andere programme/dienste laufen usw. d. h. die vergleiche sind nicht sonderlich aussagekräftig, aber ich denke das ergebnis spricht für sich (wie gesagt, falls alles richtig ist).
das maßgebliche an den screenshots ist die zeit (statusbar rechts unten).
|