![]() |
Re: Eindeutiger Vergleich für große Dateien gesucht
@supermuckl:
mit was willst du vergleichen? mit TFileStream? |
Re: Eindeutiger Vergleich für große Dateien gesucht
jep
|
Re: Eindeutiger Vergleich für große Dateien gesucht
Liste der Anhänge anzeigen (Anzahl: 2)
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; ![]() und hier die prozedur die mittlerweile entstanden ist.
Delphi-Quellcode:
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.
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; 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). |
Re: Eindeutiger Vergleich für große Dateien gesucht
Ich will mal nicht unken, aber 0,20 Sekunden KANN NICHT SEIN, bei keiner Festplatte der Welt!
[Nachtrag] Modifizier die Routine mal so (rote Stellen), dann bekommst du mit, ob ein Fehler aufgetreten ist (was ich mir denke):
Code:
function CompareFilesMemoryMapped(const File1, File2: String; SysAllocSize: Cardinal): [color=red]integer[/color];
var CurSize: DWord; CurPos: Int64; hFile1, hFile2: THandle; hMap1, hMap2: THandle; FileSize: Int64; P1, P2: Pointer; begin [color=red]Result := -1;[/color] 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 [color=red]if CompareMem(P1, P2, CurSize) then Result := 1 else Result := 0;[/color] 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; |
Re: Eindeutiger Vergleich für große Dateien gesucht
wie gesagt, es können noch fehler enthalten sein.
ich habe mal das boolean statement durch integer ersetzt und bekomme zwar auch je nach datei mal eine -1 zurück, aber soweit ich das sehe nur deshalb, weil die dateien ungleich sind. doppelte (gleiche/identische) dateien werden richtig bestimmt. ich gebe dir recht, die benötigte zeit ist absolut erstaunlich, aber selbst mit breakpoints scheint er zumindest bei fragwürdigen dateien alles korrekt auszuführen. wo könnte der fehler sein? edit: jetzt habe ich mal negaH's RaiseLastWin32Error wieder aktiviert. ich bekomme einen "System Error Code 1132: Die angegebene Basisadresse oder Dateioffset ist falsch ausgerichtet." werde mal überprüfen wie und warum. danke für den hinweis! |
Re: Eindeutiger Vergleich für große Dateien gesucht
Ziehe mal eine weitere Kopie der doppelten Datei und ändere in dieser Datei möglichst nur 1 Byte exakt in der Mitte der Datei.
Auch ich meine das 0.2 Sekunden enorm schnell ist, einfach zu schnell. Das Result auf Integer zu setzen ist keine gute Idee und lass doch mal alle RaiseLastWin32Error drinnen. Falls nämlich irgendeine API Funktion fehlschlägt so wird eine Exception auftreten und schwups finden wir den eventuellen Fehler. Gruß Hagen |
Re: Eindeutiger Vergleich für große Dateien gesucht
@negaH:
Zitat:
Zitat:
jetzt weiß ich auch die stelle:
Delphi-Quellcode:
edit2:
if P2 <> nil then
try Result := CompareMem(P1, P2, CurSize); finally UnmapViewOfFile(P2); end else RaiseLastWin32Error; // <- hier kommt die AV ![]() "The base address or the file offset specified does not have the proper alignment." "ERROR_MAPPED_ALIGNMENT" muss mal kucken wann und weshalb der auftritt. edit3: quelle: ![]() Zitat:
|
Re: Eindeutiger Vergleich für große Dateien gesucht
ich würde dich auch noch bitten (wenn du die fehler korrigiert hast) auch noch meine methode zu testen, da ich damit mit größeren blöcken arbeite und mach meiner theorie bei großen dateien, dort mehr speed rauskommen KÖNNTE
Delphi-Quellcode:
function SameFile(File1,File2:String):boolean;
var s1,s2:Tfilestream; block:int64; buffer1,buffer2: string; begin result := false; try s1 := Tfilestream.Create(File1,fmOpenRead); s2 := Tfilestream.Create(File2,fmOpenRead); if s1.Size <> s2.Size then begin result := false; end else begin s1.Position := 0; s2.Position := 0; block := 10485760; //10MB hier eventuell mal verschiedene werte ausprobieren (1,10,20,30,100) if s1.Position+block > s1.Size-1 then block := s1.Size-s1.Position; result := true; setlength(buffer1,block); setlength(buffer2,block); while( s1.Position <> s1.Size ) do begin if s1.Position+block > s1.Size-1 then block := s1.Size-s1.Position; s1.Read(buffer1[1],block); s2.Read(buffer2[1],block); if buffer1 <> buffer2 then begin result := false; break; end; end; end; finally s1.Free; s2.Free; end; end; |
Re: Eindeutiger Vergleich für große Dateien gesucht
Liste der Anhänge anzeigen (Anzahl: 1)
den fehler hab ich zwar noch nicht korrigiert, aber vorhin deine methode getestet.
bei gleichem verzeichnis wie oben hat es 715 sek. gedauert. |
Re: Eindeutiger Vergleich für große Dateien gesucht
@supermuckl: bezüglich der performance (i/o u. mmf) habe ich einen relativ interessanten artikel gefunden:
![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:17 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