Avatar billede justincase1089 Nybegynder
12. juni 2002 - 14:12 Der er 39 kommentarer og
1 løsning

Sammenligne filer

Hejsa

Jeg søger en stump kode, der er i stand til at sammenligne alle slags filer, både binære og textfiler. Og fortælle mig, om de er forskellige. Jeg behøver ingen information om hvor i filerne der er forskelle, bare en boolean eller noget i den retning. Er der en af jer der har en stump kode liggende?

MVH Justin Case
Avatar billede borrisholt Novice
12. juni 2002 - 14:18 #1
Function GetCheckSum (const FileName : TFileName) : Integer;
var
  F : File of Integer;
  Fsize : Integer;
  Buffer : Array [0..500] of Integer;
begin
  FileMode := 0;
  AssignFile ( F , FileName);
  Reset ( F );
  Seek ( F , FileSize ( F ) div 2);
  Fsize := FileSize( F )-1-FilePos( F );
  if Fsize > 500 then Fsize := 500;
  BlockRead ( F, Buffer, Fsize);
  CloseFile ( F );
    asm
      xor eax, eax
      xor ecx, ecx
      lea edx , Buffer
    @again:
      add eax, [edx + 4*ecx]
      inc ecx
      cmp ecx, fsize
    jl @again
      mov @result, eax
    end;
end;

Det her kode kan give dig en entydig check sum på en fil .. Hvis tallene er en så ER det den samme fil. Ellers ikke.

Jens B
Avatar billede hermandsen Juniormester
12. juni 2002 - 14:23 #2
Jeg lavede en gang (lang tid siden) det her:

function IsSameFile(var F1, F2: File): Boolean; overload;
var
  OldSeek1, OldSeek2, Seeker, Size1, Size2, NumRead: Integer;
  Buf1, Buf2: array [1..2048] of Char;
begin
  OldSeek1 := FilePos(F1);
  OldSeek2 := FilePos(F2);
  Size1 := FileSize(F1);
  Size2 := FileSize(F2);
  Seeker := Min(Size1, Size2)-2048;
  if Seeker < 0 then
  begin
    FillChar(Buf1, 2048, 0);
    FillChar(Buf2, 2048, 0);
    Seeker := 0;
  end;
  Seek(F1, Seeker);
  Seek(F2, Seeker);
  if Seeker = 0 then
  begin
    BlockRead(F1, Buf1, Min(Size1, Size2), NumRead);
    BlockRead(F2, Buf2, NumRead);
  end
  else
  begin
    BlockRead(F1, Buf1, 2048);
    BlockRead(F2, Buf2, 2048);
  end;
  Seek(F1, OldSeek1);
  Seek(F1, OldSeek2);
  Result := Buf1 = Buf2;
end;

function IsSameFile(FileName1, FileName2: String): Boolean; overload;
var
  F1, F2: File;
  OldFileMode: Byte;
begin
  OldFileMode := FileMode;
  FileMode := 0;
  AssignFile(F1, FileName1);
  Reset(F1, 1);
  AssignFile(F2, FileName2);
  Reset(F2, 1);
  Result := IsSameFile(F1, F2);
  CloseFile(F1);
  CloseFile(F2);
  FileMode := OldFileMode;
end;

Dog tror jeg det er bedre at bruge Borrisholt's metode... Kunne godt se lidt hurtigere ud! ;)
Avatar billede justincase1089 Nybegynder
12. juni 2002 - 14:24 #3
Barsk ... jeg har ikke testet det, men jeg kan se at syntaxen er korrekt ..... NOT
Avatar billede borrisholt Novice
12. juni 2002 - 14:29 #4
jeg har en enkelt gang postet den før på eksperten . Der var det også kommentarer med :

Function GetCheckSum (const FileName : TFileName) : Integer;
var
  F : File of Integer;
  Fsize : Integer;
  Buffer : Array [0..500] of Integer;
begin
  FileMode := 0;
  AssignFile ( F , FileName);
  Reset ( F );
  Seek ( F , FileSize ( F ) div 2);
  Fsize := FileSize( F )-1-FilePos( F );
  if Fsize > 500 then
    Fsize := 500;
  BlockRead ( F, Buffer, Fsize);
  CloseFile ( F );
    asm
      xor eax, eax //NULSTILL  eax det skal bruges til at tælle sammen i
      xor ecx, ecx //NULSTILL  ecx det skal bruges til at holde vores tælle variabel
      lea edx , Buffer //Put adressen på Buffer over i edx registeret.
    @again: //En label vi kan hoppe til  PRÆCIS magen til en label i pascal (Ikke at forveksle med TLabel)
      add eax, [edx + 4*ecx]
//En integer fylder 4 BYTE (32 bit) så hvis vi skal have fat i Et eller andet element i vores
//Buffer array ligger det på adressen Starten af array + (4*Nummeret på elementet)
//Adressen på starten af arrayet ligger i edx registeret. Vores tæller variabel er ecx så
//regnestykket hedder edx + 4*ecx. Da vi ikke skal have adressen men der der ligger på adressen
//stopper vi det hele ind i []. Det hele bliver stoppet over i eax.
      inc ecx //tæl  ecx op med 1 (inc er en forkortelse af increase)
      cmp ecx, fsize  //sammenlign (cmp er en forkortelse af compare)
    jl @again //hvis ecx < fsize  så goto again lablen vi satte før (jl er en forkortelse af Jump less)
      mov @result, eax //kom resultater af vores tællen sammen over i result
    end;
end;


jens B
Avatar billede borrisholt Novice
12. juni 2002 - 14:29 #5
Avatar billede justincase1089 Nybegynder
12. juni 2002 - 14:32 #6
Ja, men det kom ikke frem ved at søge på "sammenligne"
Avatar billede zimp Nybegynder
13. juni 2002 - 17:43 #7
Du kunne starte med at sammenligne filstørrelsen inden du laver checksum, det kunne spare en masse tid.
Avatar billede justincase1089 Nybegynder
13. juni 2002 - 17:46 #8
det er ikke særlig sikkert .. jeg har brug for noget der er meget præcist
Avatar billede zimp Nybegynder
13. juni 2002 - 18:25 #9
Prøv at læse min kommentar igen ;)
Avatar billede justincase1089 Nybegynder
13. juni 2002 - 18:26 #10
Åååh ... ja. ... jeg pudser lige brillerne ;-)
Avatar billede borrisholt Novice
14. juni 2002 - 08:39 #11
Det der tager tiden er at finde filen på HD'en det andet tager ikke lang tid.

Jens B
Avatar billede justincase1089 Nybegynder
14. juni 2002 - 09:44 #12
Hmm .... Jens, har du prøvet dit eksempel? Jeg har lidt problemer med at få koden til at identificere forskelle. Jeg har lavet 2 sprit nye applilationer i Delphi. I den ene er der en knap med en caption := button1 og i det andet med button caption := button2. Programmet beregner identiske checksummer for programmerne, selvom de er forskellige :/
Avatar billede zimp Nybegynder
14. juni 2002 - 10:23 #13
Funktionen GetCheckSum laver kun checksum på max. 500 bytes midt i filen. Det er en meget hurtig måde at gøre det på, men langt fra nøjagtig så vidt jeg kan se.

Du er nødt til at sammenligne hver eneste byte i de to filer for at være sikker, og så er det at starte med en sammenligning på filstørrelser kan spare en bunke tid, især hvis det er store filer.
Avatar billede borrisholt Novice
14. juni 2002 - 11:26 #14
prøv den her :
Function GetCheckSum ( FileName : String) : Integer;
var
  MemoryStream : TMemoryStream;
  FSize : Integer;
  P : PChar;
begin
  MemoryStream := TMemoryStream.Create;
  MemoryStream.LoadFromFile(FileName);
  p := MemoryStream.Memory;
  Result := 0;
  {$R-}
  for FSize := 0 to MemoryStream.Size do
    Result := Result + Integer(p[FSize]);
  {$R+}
  MemoryStream.Free;
end;

Kræver dog minst D5 ellers kan du risikere at få en range check error.

Jens B
Avatar billede justincase1089 Nybegynder
14. juni 2002 - 11:26 #15
Ok, jeg sammenligner størrelsen. De er ens. Og hvad så, lad os sige, at der kun er ændret en byte i enden af programmet, der fylder 1 mb. Så er det hverken størrelse eller 500 byte i midten der er ændret.
Avatar billede justincase1089 Nybegynder
14. juni 2002 - 11:27 #16
Tak Jens, den prøver jeg
Avatar billede justincase1089 Nybegynder
14. juni 2002 - 11:29 #17
skal det ikke være
for FSize := 0 to MemoryStream.Size-1 do
Avatar billede borrisholt Novice
14. juni 2002 - 11:31 #18
jo selvfølgelig ..

Er du kvik not til at fortælle mig hvrofor det andet går godt ? :-)

Jens B
Avatar billede borrisholt Novice
14. juni 2002 - 11:45 #19
den her er lidt hurtigere :
Function GetCheckSum ( FileName : String) : Integer;
var
  MemoryStream : TMemoryStream;
  i, FSize : Integer;
  P : PChar;
begin
  MemoryStream := TMemoryStream.Create;
  MemoryStream.LoadFromFile(FileName);
  p := MemoryStream.Memory;
  Result := 0;
  FSize := MemoryStream.Size div 4;
  {$R-}
  for i := 0 to FSize do
    inc(Result, Integer(p[FSize]));
  {$R+}
  MemoryStream.Free;
end;


Jens B
Avatar billede justincase1089 Nybegynder
14. juni 2002 - 11:46 #20
Ikke umiddelbart .. enlighten me please
Avatar billede borrisholt Novice
14. juni 2002 - 11:50 #21
fordi jeg har slåer Range Checking fra : {$R-}

Jens B
Avatar billede justincase1089 Nybegynder
14. juni 2002 - 11:53 #22
aha :)
Avatar billede zimp Nybegynder
14. juni 2002 - 11:57 #23
BorrisHolt, i dit andet eksempel kan du misse 1-3 bytes, alt afhængig af hvor stor filen er ;)

Hvor store er dine filer justincase? Hvis de er meget store vil dit program få et enorm ram forbrug eftersom hele filen loades in på én gang.
Avatar billede borrisholt Novice
14. juni 2002 - 12:18 #24
Øøøh ja det er også en fejl ...  Det er sq da godt i er vårne .. DEet var fordi jeg var ved at ekpermentere med noget andet : Noget ASM.

Vi bringer lige en opdatering :

Function GetCheckSum (FileName : String) : Integer;
var
  MemoryStream : TMemoryStream;
  i, FSize : Integer;
  P : PChar;
begin
  MemoryStream := TMemoryStream.Create;
  MemoryStream.LoadFromFile(FileName);
  p := MemoryStream.Memory;
  Result := 0;
  FSize := MemoryStream.Size -1;
  {$R-}
  for i := 0 to FSize do
    inc(Result, Integer(p[FSize]));
  {$R+}
  MemoryStream.Free;
end;

Jens B
Avatar billede justincase1089 Nybegynder
14. juni 2002 - 12:34 #25
Filerne varierer fra nogle få kb til op til 10 mb. Sammenligningen kommer nu til at køre på en server med adskillige GB ram og RAID, så det kommer ikk til at betyde noget .... så længe der ikke er leaks ;-)
Avatar billede borrisholt Novice
14. juni 2002 - 12:37 #26
Det er der ikke i min proc.

Jens B
Avatar billede justincase1089 Nybegynder
14. juni 2002 - 12:39 #27
Nej, glimrende
Avatar billede borrisholt Novice
14. juni 2002 - 12:42 #28
skal du så også vide hvornår der sker ændringer på din HD ?
Avatar billede justincase1089 Nybegynder
14. juni 2002 - 12:46 #29
Nej, ellers tak.
Sammenligningen af filerne skal jeg bruge i en natlig bygning af omkring 300 dller og exefiler og derudfra bestemme, om der skal incrementeres i en efterfølgende versionsstempling. Så denne sammenligning sker afhængig af en tidsevent
Avatar billede borrisholt Novice
14. juni 2002 - 13:00 #30
hvad med et træ til at stille den slags op i ?

Jens B
Avatar billede zimp Nybegynder
14. juni 2002 - 13:07 #31
Her er mit bud på hvordan den funktion skal de ud :o) (jeg kunne ikke lade være)

type
  TFileCompareResult = (fcrEqual, fcrDiferentSizes, fcrDifferentContent, fcrFileNotFound, fcrUnknownError);

function IsSameFile(File1, File2: string): TFileCompareResult;
const BUFLEN = 65536;
var
  F1, F2      : file;
  Buf1, Buf2  : array[0..BUFLEN-1] of byte;
  Bytes      : integer;
begin
  try
    if (FileExists(File1) and FileExists(File2)) then begin
      AssignFile(F1, File1);
      AssignFile(F2, File2);
      Reset(F1, 1);
      Reset(F2, 1);
      if FileSize(F1) = FileSize(F2) then begin
        Result := fcrEqual;
        while not Eof(F1) do begin
          BlockRead(F1, Buf1[0], BUFLEN, Bytes);
          BlockRead(F2, Buf2[0], BUFLEN, Bytes);
          if not CompareMem(@Buf1[0], @Buf2[0], Bytes) then begin
            Result := fcrDifferentContent;
            break;
          end;
        end;
      end else begin
        Result := fcrDiferentSizes;
      end;
      CloseFile(F1);
      CloseFile(F2);
    end else begin
      Result := fcrFileNotFound;
    end;
  except
    on e: exception do begin
      MessageBox(0, pchar(E.Message), 'ok', mb_ok);
    Result := fcrUnknownError;
    end;
  end;
end;
Avatar billede zimp Nybegynder
14. juni 2002 - 13:08 #32
Ooopsie, slet lige messageboxen! Den var bare til test, sorry

Exception delen skal bare se således ud:

  except
    Result := fcrUnknownError;
  end;
Avatar billede justincase1089 Nybegynder
14. juni 2002 - 13:13 #33
zimp : Tak

Jens B : Ellers tak .. hele scheduleringen af bygningen af filerne klares fra en database.
Avatar billede borrisholt Novice
14. juni 2002 - 13:43 #34
zimp ... Brug en stream i stedet. Det er hurtigere.

Jens B
Avatar billede borrisholt Novice
14. juni 2002 - 13:59 #35
noget alla det her :

type
  TFileCompareResult = (fcrEqual, fcrDiferentSizes, fcrDifferentContent, fcrUnknownError);

function IsSameFile(File1, File2: string): TFileCompareResult;
var
  Stream1, Stream2 : TMemoryStream;
begin
  try
    Stream1  := TMemoryStream.Create;
    Stream2  := TMemoryStream.Create;
  try
    Stream1.LoadFromFile(File1);
    Stream2.LoadFromFile(File2);

    if Stream1.Size = Stream2.Size then
        if CompareMem(Stream1.Memory, Stream2.Memory, Stream1.Size) then
          Result := fcrEqual
        else
          Result := fcrDifferentContent
    else
      Result := fcrDiferentSizes;

  finally
    Stream1.Free;
    Stream2.Free;
  end;
  except
    Result := fcrUnknownError;
  end;
end;


Jens B
Avatar billede borrisholt Novice
14. juni 2002 - 13:59 #36
Det der tager lang tid er at læse fra HD'en ar arbejde i ram er hurtigt !

Jens B
Avatar billede zimp Nybegynder
14. juni 2002 - 14:03 #37
Det går nu ikke hurtigere fordi du bruger en stream, det skal loades alligevel, og ulempen ved det ovenstående er du loader hele filen på en gang, det giver et stort ram forbrug.
Avatar billede borrisholt Novice
14. juni 2002 - 14:09 #38
ja forskellen er at jeg tilgår HD' en gang pr fil. Du til går den flere gange. Det er det der er min pointer, og derfor jeg påstår at mine streams er hurtigere.

Jens B
Avatar billede borrisholt Novice
14. juni 2002 - 14:10 #39
fordelen ve en check sum frem for CompareMem er at Tallet sammen med filnavnet er meget tæt på et unik ID

Jens B
Avatar billede zimp Nybegynder
14. juni 2002 - 14:25 #40
Jeg lavede lige en speedtest, på 1MB fil gik det ca. 2-3 gange så langsomt at bruge en stream, som selv at læse med BlockRead.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester