AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi Delphi Eindeutiger Vergleich für große Dateien gesucht
Thema durchsuchen
Ansicht
Themen-Optionen

Eindeutiger Vergleich für große Dateien gesucht

Ein Thema von dahead · begonnen am 2. Aug 2005 · letzter Beitrag vom 10. Mai 2014
Antwort Antwort
Seite 6 von 12   « Erste     456 78     Letzte »    
Benutzerbild von dahead
dahead

Registriert seit: 16. Mai 2005
620 Beiträge
 
#51

Re: Eindeutiger Vergleich für große Dateien gesucht

  Alt 3. Aug 2005, 11:59
hallo,

ja, das mit .Read ist mir jetzt klar (s. oben).

1.) GetFileSize speichere ich bereits als Int64.
2.) ok, werde ich einbauen.
3.) ok
4.) ja, so habe ich mir das auch gedacht. ich muss jetzt nur aus diesen beiden prozeduren (FilesAreBinaryEqual u. TMemoryMappedFile.Create) eine basteln, die das besagte problem löst.

das mit den 64 kb blöcken ist ebenfalls logisch, wie du siehst habe ich ja auch in der TFileStream variante daten in dieser block größe eingelesen.

D.h. man sollte die Buffergröße inkrementell so lange erhöhen bis sich die größte Performance pro Byte ergibt. ja, das wäre am besten.

aus der msdn:
Zitat:
dwFileOffsetLow: A low-order DWORD of the file offset where the view is begins. The combination of the high and low offsets must specify an offset within the file that matches the memory allocation granularity of the system, or the function fails. That is, the offset must be a multiple of the allocation granularity. To obtain the memory allocation granularity of the system, use the GetSystemInfo function, which fills in the members of a SYSTEM_INFO structure.
d.h. ich muss erst ermitteln, welchen wert das jeweilige system überhaupt zulässt.

edit:

Delphi-Quellcode:
function GetSystemAllocationGranularity: Cardinal;
var
  PSysInfo: TSystemInfo;
begin
  GetSystemInfo(PSysInfo);
  Result := PSysInfo.dwAllocationGranularity;
end;
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#52

Re: Eindeutiger Vergleich für große Dateien gesucht

  Alt 3. Aug 2005, 13:03
GetSystemAllocationGranularity ermittelt also die Basis deiner "Buffergröße". Dein Buffer zb. 64Kb muß also ohne Rest durch GetSystemAllocationGranularity teilbar sein. In diesem Moment wird dwFileOffsetLo/Hi automatisch den geforderten Bedinungen gerecht, denn nach jedem Buffervergleich inkrementierst du ja die Int64-Offsets beider Dateien um die Buffergröße. dwFileOffsetLow = Int64Offset mod $100000000; dwFileOffsetHigh := Int64Offset div $100000000;

Diese zusätzliche Bedingung des API's zeigt sehr deutlich wie Hardwarenah die Funktionalität eigentlich ist.

Gruß Hagen
  Mit Zitat antworten Zitat
Benutzerbild von dahead
dahead

Registriert seit: 16. Mai 2005
620 Beiträge
 
#53

Re: Eindeutiger Vergleich für große Dateien gesucht

  Alt 3. Aug 2005, 13:28
Ja, das stimmt. bei meinem system ist der durch GetSystemAllocationGranularity ermittelte buffer sogar genau 64 kb groß.

das TMemoryMappedFile erstelle ich durch eine leicht von deiner version abgewandelte prozedur (ich habe mir z.b. die property fSize eingebaut):

Delphi-Quellcode:
constructor TMemoryMappedFile.Create(const FileName: String);
var
  P: Pointer;
begin
  fFileHandle := FileOpen(FileName, fmOpenRead or fmShareDenyWrite);

  if fFileHandle = INVALID_HANDLE_VALUE then
   raise Exception.Create(Format('Datei %s konnte nicht geöffnet werden!', [Filename]));

 //if fFileHandle > 0 then
 if fFileHandle <> INVALID_HANDLE_VALUE then
  begin
   fSize := GetFileSize(fFileHandle, nil);
   if fSize > 0 then
    begin
     fFileMap := CreateFileMapping(fFileHandle, nil, PAGE_READONLY, 0, 0, nil);
     {
    if fFileMap <> 0 then
      begin
      P := MapViewOfFile(
        fFileMap,
        FILE_MAP_READ,
        0,    // beginn der map
        0,    //
        0);  // zu lesende bytes, fSize liest kompl. Datei ein

      if P <> nil then
        inherited SetPointer(P, fSize);
      end;
      }


    end;
  end;

  inherited Create;
end;
wie du siehst, frage ich im create nicht MapViewOfFile ab, da ich dies erst beim vergleich mache.

hier die vergleichs prozedur:

Delphi-Quellcode:
function Tmf.CompareMemoryMappedFiles(const File1, File2: String): Boolean;
var
  MMF1, MMF2: TMemoryMappedFile;
  P1, P2: Pointer;
  CurPos: Int64;
  AllocGran: Cardinal;
begin
  Result := False;
  AllocGran := GetSystemAllocationGranularity; //Todo: hier raus nehmen, nicht bei jedem aufruf erneut abfragen
  MMF1 := TMemoryMappedFile.Create(File1);
  MMF1.Position := 0;
  try
    MMF2 := TMemoryMappedFile.Create(File2);
    MMF2.Position := 0;
    try
      begin
       CurPos := 0;
       while CurPos < MMF1.Size do
        begin
         P1 := MapViewOfFile(MMF1.fFileMap, FILE_MAP_READ, CurPos, CurPos + AllocGran, AllocGran);
         P2 := MapViewOfFile(MMF2.fFileMap, FILE_MAP_READ, CurPos, CurPos + AllocGran, AllocGran);
         if not CompareMem(P1, P2, AllocGran) then //hier kriege ich die AV
          Exit;
         Inc(CurPos, AllocGran);
        end;
       Result := True;
      end;
    finally
      MMF2.Free;
    end;
  finally
    MMF1.Free;
  end;
end;
allerdings bekomme ich bei CompareMem eine AV. ich glaube ich übergebe entweder die Length von Comparemem nicht korrekt oder es hapert bereits bei der P1, P2 pointer zuweisung.

mein problem ist auch, dass ich durch MapViewOfFile nicht die Length kenne. daher übergebe ich AllocGran.
  Mit Zitat antworten Zitat
Benutzerbild von dahead
dahead

Registriert seit: 16. Mai 2005
620 Beiträge
 
#54

Re: Eindeutiger Vergleich für große Dateien gesucht

  Alt 3. Aug 2005, 13:31
ich glaube ich habe den fehler gefunden:

Delphi-Quellcode:
MapViewOfFile(MMF1.fFileMap, FILE_MAP_READ, CurPos, CurPos + AllocGran, AllocGran);
MapViewOfFile(MMF2.fFileMap, FILE_MAP_READ, CurPos, CurPos + AllocGran, AllocGran);
if not CompareMem(@MMF1.fFileMap, @MMF2.fFileMap, AllocGran) then
 Exit;
so gehts. ist das korrekt? bzw. ist es auch korrekt das MapViewOfFile im Create wegzulassen. ich denke schon, oder?

edit: tut mir leid dass ich hier soviel poste.
diese 'lösung' ist nicht korrekt. die überprüfung ergibt hierbei immer false, er spring bei comparemem raus. ist also keine lösung.
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#55

Re: Eindeutiger Vergleich für große Dateien gesucht

  Alt 3. Aug 2005, 14:26
Delphi-Quellcode:
 P1 := MapViewOfFile(MMF1.fFileMap, FILE_MAP_READ, CurPos, CurPos + AllocGran, AllocGran);
 P2 := MapViewOfFile(MMF2.fFileMap, FILE_MAP_READ, CurPos, CurPos + AllocGran, AllocGran);
 if not CompareMem(P1, P2, AllocGran) then Exit;
 Inc(CurPos, AllocGran);
Ich sehe zwei Fehler

1.) MapViewOfFile() erwartet den Dateioffset der gemappt werden soll als 2x DWord. Du musst also CurPos als Int64 in zwei DWords zerlegen

2.) MapViewOfFile() kann fehlschlagen und dann ist P1 und/oder P2 = nil !

Nun, da du CurPos in MapViewOfFile() FALSCH übergibst ist sogar P1 und P2 = nil und daher deine AV.
Richtiger so


Delphi-Quellcode:
var
  CurPosHi,CurPosLo: DWord;
  CurSize: DWord;
  CurPos: Int64;
  FileHandle1, FileHandle2: THandle;
  MapHandle1, MapHandle2: THandle;
  FileSize: Int64;
begin
  Result := False;
  FileHandle1 := CreateFile(..., FileName1, ...);
  if FileHandle1 <> INVALID_HANDLE_VALUE then
  try
    FileHandle2 := CreateFile(..., FileName2, ...);
    if FileHandle2 <> INVALID_HANDLE_VALUE then
    try
      FileSize := GetFileSizeInt64(FileHandle1);
      if FileSize = GetFileSizeInt64(FileHandle1) then
      begin
        Result := True;
        if FileSize1 > 0 then
        begin
          MapHandle1 := CraeteFileMapping(FileHandle1);
          if MapHandle1 <> INVALID_HANDLE_VALUE then
          try
            MapHandle2 := CreateFileMapping(FileHandle2);
            if MapHandle2 <> INVALID_HANDLE_VALUE then
            try
              CurSize := FileSize mod AllocGran;
              if CurSize = 0 then CurSize := AllocGran;
              CurPos := FileSize - CurSize;
              repeat
                CurPosHi := CurPos div 2^32;
                CurPosLo := CurPos mod 2^32;
                P1 := MapViewOfFile(MapHandle1, ..., CurPosHi, CurPosLo, CurSize);
                if P1 <> nil then
                try
                  P2 := MapViewOfFile(MapHandle2, ..., 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
              CloseFileMapping(MapHandle2);
            end else RaiseLastWin32Error;
          finally
            CloseFileMapping(MapHandle1);
          end else RaiseLastWin32Error;
        end;
      end;
    finally
      CloseFile(FileHandle2);
    end else RaiseLastWin32Error;
  finally
    CloseFile(FileHand1e1);
  end else RaiseLastWin32Error;
end;
Eventuelle Fehler in obigen Pseudocode darfst du behalten

Die Idee das Filemapping erst wirklich in der Vergleichs-Operation zu erzeugen halte ich für absolut richtig. Das wäre mein nächster Vorschlag gewesen. Alledings hätte ich sogar noch das CreateFileMapping() mit in die Vergleichsfunktion integriert.

Gruß hagen

Edit: shit nun zum 3. mal eine Änderung.
Code arbeitet die Datei nun von Hinten nach Vorne ab, da die Wahrscheinlichkeit das sich de dateien am Ende unterscheiden höher sein dürfte. Das Exit/Break wurde entfernt, so ist es sauberer. Try Finallys niemals vergessen !!
  Mit Zitat antworten Zitat
Benutzerbild von dahead
dahead

Registriert seit: 16. Mai 2005
620 Beiträge
 
#56

Re: Eindeutiger Vergleich für große Dateien gesucht

  Alt 3. Aug 2005, 14:41
hallo negaH,

erstmal danke für deine ausführliche hilfe.

ich werde versuchen deinen vorschlag umsetzen. ich melde mich wieder, wenn es geklappt hat und poste dann die fertige (hoffentlich) prozedur.

nochmals vielen dank für deine hilfe!
  Mit Zitat antworten Zitat
Benutzerbild von dahead
dahead

Registriert seit: 16. Mai 2005
620 Beiträge
 
#57

Re: Eindeutiger Vergleich für große Dateien gesucht

  Alt 3. Aug 2005, 15:09
wow!

das muss ich aber erstmal verdauen, sprich für meinen bestehenden code anpassen. eventuell mach ich den vergleich dann wirklich in nur dieser einen prozedur (sprich create u. vergleich in einer prozedur).

achja, was mir gerade noch einfällt: bevor du vorhin deinen code bearbeitet hattest, hab ich versucht zu testen. allerdings meckert bei mir der compiler bei 2^32. da sagt er mir pointer type required. er denkt wohl dass ich den pointer dereferenzieren möchte.

das ^ bedeutet doch "hoch" (z.B. 2^2=4), oder täusche ich mich?

nochmals vielen dank für deine mühe!
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#58

Re: Eindeutiger Vergleich für große Dateien gesucht

  Alt 3. Aug 2005, 16:15
Jo 2^32 = 2 hoch 32 = 1 shl 32 =

Delphi-Quellcode:

const
  Power2of32: Int64 = $100000000;
Alle 2^32 mit der Konstanten Power2of32 ersetzen, oder besser so:

Delphi-Quellcode:
CurPosLo := Int64Rec(CurPos).Lo;
CurPosHi := Int64Rec(CurPos).Hi;
Du könnste dann sogar die beiden Variablen weg optimieren und gleich mit Int64Rec() casten -> SysUtils.

Ich würde ebenfalls eine einzigste Function coden, warum will man noch eine aufwendige Klasse für diese Spezialaufgabe coden ?

Gruß Hagen
  Mit Zitat antworten Zitat
Benutzerbild von dahead
dahead

Registriert seit: 16. Mai 2005
620 Beiträge
 
#59

Re: Eindeutiger Vergleich für große Dateien gesucht

  Alt 3. Aug 2005, 16:46
ah, danke für diesen hinweis!

Zitat:
Ich würde ebenfalls eine einzigste Function coden, warum will man noch eine aufwendige Klasse für diese Spezialaufgabe coden ?
ja, ist ohne die extra klasse sogar kompakter/übersichtlicher und da ich sowieso in keiner anderen prozedur darauf zugreifen muss, habe ich es wie in deinem beispiel-code gelöst.

ich bin zwar noch am testen (speicherlücken usw.) aber wenn die abgeschlossen sind, poste ich hier den fertigen code. vielleicht kann ja noch jemand was damit anfangen, bzw. vielleicht findet ihr ja noch fehler.

vielen dank nochmal an alle die mitgeholfen haben, insbesondere an dich negaH!
  Mit Zitat antworten Zitat
supermuckl

Registriert seit: 1. Feb 2003
1.340 Beiträge
 
FreePascal / Lazarus
 
#60

Re: Eindeutiger Vergleich für große Dateien gesucht

  Alt 3. Aug 2005, 17:27
mal ne doofe frage.
wieso benutzt ihr MMFs für "non Random Reads" ?
den vorteil den dir MMF bringt (das cachen dem OS überlassen) womit random reads eventuell schneller ausgeführt werden können, wirkt sich eventuell sogar negativ auf sequenzielle reads aus, wie ich sie beim comparen mache ?!

wenn ich 10MB oder sogar 30 aufeinmal von der HDD lese, müsste doch da der HDDcache positiv beschleunigen, wobei ich mir bei MMF da immernoch nicht sicher bin.

wieso also mit kanonen auf spatzen schießen ?

ein vergleich wäre sinnvoll
Das echte Leben ist was für Leute...
... die im Internet keine Freunde finden!
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 6 von 12   « Erste     456 78     Letzte »    


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:49 Uhr.
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