![]() |
Re: Eindeutiger Vergleich für große Dateien gesucht
@negaH:
gerade lese ich noch einen beitrag von dir über RPNG's (stichwort: radioaktiver zerfall), und da kommt schon wieder eine antwort auf diesen thread, danke! zum thema: ja, memory mapped files habe ich in diesem zusammenhang auch schonmal gehört (genauer gesagt heute mittag, als ich nach einer schnellen möglichkeit für den byte-per-byte vergleich gesucht habe: ![]() danke für deinen code! ich werde ihn mir morgen früh mal genauer ansehen und testen. |
Re: Eindeutiger Vergleich für große Dateien gesucht
moin hagen,
ich denke nicht, das man mit diesen Funktionen einen wesentlichen Geschwindigkeitszuwachs erzielen wird, finde aber FileOpen() logischer und einfacher zu Hand haben. (zwecks Portierung wirst du damit keine Probleme bekommen, mit der API vielleicht schon) |
Re: Eindeutiger Vergleich für große Dateien gesucht
also ich habe während ich vorhin den o.g. beitrag von negaH gelesen habe, einen test mit TFileStream laufen lassen.
dabei wurden wieder die beiden doppelten dateien verglichen (s. screenshot irgendwo vorne). dauer ca. 700 sekunden. edit: also byte-per-byte. gerade habe ich negaH's code eingebaut und der vergleich dauert 3,44 sekunden. erstaunlich. ich muss mir mal die hilfe zu den api befehlen (CreateFileMapping, usw.) ansehen, damit ich genauer verstehe, was sich hinter memory mapped files genau verbirgt. edit2: falls du es auch testen willst, hier der entsprechende code (ohne negaH's o.g. code. den habe ich einfach mal in die unit mit reinkopiert. einzige änderung war, dass ich Tmmf in TMemoryMappedFile umbenannt habe):
Delphi-Quellcode:
function Tmf.FilesAreBinaryEqual(const File1, File2: String): Boolean;
const BlockSize = 65536; var //FSFile1, FSFile2: TFileStream; FSFile1, FSFile2: TMemoryMappedFile; L1, L2: Integer; B1, B2: Array[1..BlockSize] of Byte; begin Result := False; //FSFile1 := TFileStream.Create(File1, fmOpenRead or fmShareDenyWrite); FSFile1 := TMemoryMappedFile.Create(File1); try //FSFile2 := TFileStream.Create(File2, fmOpenRead or fmShareDenyWrite); FSFile2 := TMemoryMappedFile.Create(File2); 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; |
Re: Eindeutiger Vergleich für große Dateien gesucht
Das hört sich doch sehr gut.
Könnte gut möglich sein, dass das mit der Auslagerungsdatei zusammenhängt. |
Re: Eindeutiger Vergleich für große Dateien gesucht
@DaHead:
;) denoch machst du den Vergleich sehr umständlich !
Delphi-Quellcode:
das geht einfacher mit
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;
Delphi-Quellcode:
Denn das MMF hat ja schon die komplette Datei in den Speicher virtuell eingeblendet.
result := (FSFile1.Size = FSFile2.Size) and CompareMem(FSFile1.Memory, FSFile2.Memory, FSFile1.Size);
Du musst halt nur aufpassen das die beiden Dateien NICHT zu groß sind. Eine 2 Gb Datei wird man eben nicht vollständig in den Speicher einblenden können. Um denoch mit MMF's arbeiten zu können musst du dann aber mit MapViewOfFile() die Startposition + Pagegröße aus der Zieldatei stückchenweise einblenden. Am besten du baust dir eine reine API-Funktion die über das Windows-API + MMF's zwei Dateien binär vergleicht, also ohne VCL. Schneller ist das weil du immer mehr auf Zwischengepufferte Daten verzichtest, sprich keinerlei Caches und Speicherkopierungen mehr durchgeführt werden. Das OS lädt nämlich ohne Umwege die Datei in den Speicher. Aber 3,44 im Verhältnis zu 700 Sekunden hätte ich weis Gott nicht vermutet, da hätte ich Bigg mit seiner Aussage ebenfalls Recht gegeben. Bist du dir sicher das du auch wirklich die kompletten Dateien verglichen hast ? Schiebe mal ein FSFile1.Position := 0; und FSFile2.Position :=0; mit rein, oder benutze gleich meinen obigen Vorschlag. Ich kanns nämlich auch nicht so recht glauben das die MMF's rund 200x schneller sein sollen. Gruß Hagen |
Re: Eindeutiger Vergleich für große Dateien gesucht
@negaH:
ja, danke für den hinweis mit dem umständlichen code. ich war auch gerade dabei diesen zu optimieren, wollte mir allerdings vorher die entsprechenden msdn artikel zur gemüte führen.
Delphi-Quellcode:
wieviel wird hier eigentlich in den speicher gelesen? laut meiner hilfe ist der letzte parameter dwNumberOfBytesToMap ja auf 0.
P := MapViewOfFile(FMapping, FILE_MAP_READ, 0, 0, 0);
um das 2gb problem zu beheben müsste ich dwFileOffsetLow u. dwFileOffsetHigh erhöhen. was ich auch nicht ganz verstehe, ist wo bei folgendem code die erhöhung der akt. lese position stattfindet:
Delphi-Quellcode:
edit, hat sich erledigt mit der inkrementierung in obigem code, ist klar.
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; |
Re: Eindeutiger Vergleich für große Dateien gesucht
Zitat:
|
Re: Eindeutiger Vergleich für große Dateien gesucht
Zitat:
.Read setzt doch die Position immer auf das letze gelesene Byte + 1 oder? |
Re: Eindeutiger Vergleich für große Dateien gesucht
@sharky:
ja, du hast recht. ist mir gerade auch klar geworden als ich da zwei breakpoints auf die entsprechenden read stellen gesetzt habe. |
Re: Eindeutiger Vergleich für große Dateien gesucht
Zitat:
Um die MMF's richtig zu nutzen solltest du: 1.) GetFileSize() in einen Int64 speichern, also alle Zähler auf Int64 umbauen 2.) MapViewOfFile() muß mit einen (OffsetLo,OffsetHi) = Int64 arbeiten 3.) MapViewOfFile() sollte bei dwNumberOfBytesToMap mit zb. > 64Kb arbeiten 4.) die innerste Schleife muß also wiederholt mit MapVieOfFile() solche 64Kb Stückchen laden, dann mit CompareMem() vergleichen und wieder freigeben, zumindestens so lange wie sich beide Dateien gleichen Duch die Verwendung von Happen a >64Kb hast du nun nochmals einen Geschwindigkeitsvorteil. Denn nun bricht deine Laderoutine bei großen Datei die aber unterschiedlich sind viel frühzeitiger ab. Angenommen zwei 1Gb Dateien die sich aber schon in den ersten Bytes unterscheiden. Bei der jetzigen Methode muß das OS 2Gb an daten in den Speicher einlesen, das dauert. Bei der Methode mit 64Kb Stückchen geht das viel schneller. Und die Wahrscheinlichkeit das zwei gleichgroße Dateien unterschiedlich sind ist viel größer als das sie sich gleichen. Die 64Kb Stückchengröße sollte man jetzt durch Test ermitteln. Es gilt den korrekten Breakeven Point zu finden an dem die Größe der Stückchen im Verhältnis zum zeitlichen Overhead für MapViewOfFile() und UnmapViewOfFile() den schnellsten Vergleich ergibt. D.h. man sollte die Buffergröße inkrementell so lange erhöhen bis sich die größte Performance pro Byte ergibt. Ich persönlich würde dies dynamisch zur Laufzeit ermitteln. D.h. der Vergleichscode misst sich selber aus und inkremenmtiert successive die Buffergröße bis sich die größte Performance einstellt. Der Vorteil ist ja das dieser Dateivergleich sehr oft pro Session durchgeführt werden muß. Gruß Hagen |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:05 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