Einzelnen Beitrag anzeigen

Benutzerbild von dahead
dahead

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

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

  Alt 3. Aug 2005, 17: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).
Miniaturansicht angehängter Grafiken
tfilestream_316.jpg   tmemorymappedfile_973.jpg  
  Mit Zitat antworten Zitat