AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Dateien byteweise vergleichen

Ein Thema von HeikoAdams · begonnen am 14. Mai 2010 · letzter Beitrag vom 14. Mai 2010
Antwort Antwort
Seite 1 von 3  1 23      
Benutzerbild von HeikoAdams
HeikoAdams

Registriert seit: 12. Jul 2004
Ort: Oberfranken
661 Beiträge
 
FreePascal / Lazarus
 
#1

Dateien byteweise vergleichen

  Alt 14. Mai 2010, 12:08
Hallo,
da ich hier noch nichts in der Richtung gefunden habe, stelle ich meinen Code zum byteweisen Vergleich von Dateien hier einfach mal zur Diskussion:
Delphi-Quellcode:
{
Version 1.2.1:
- added try-finally-block specially requested by himitsu.

Version 1.2:
- rewritten to squeez code to minimum. Thanks to Neutral General

Version 1.1:
- rewritten for shorter code. Thanks to himitsu
- using TMemoryStream instead of TFileStream. Thanks to DeddyH
}

function ByteCompFiles(const aSourceFile, aDestFile: string): Boolean;
var
  SourceFile, DestFile: TMemoryStream;
begin
  SourceFile := TMemoryStream.Create;
  try
    DestFile := TMemoryStream.Create;
    try
      SourceFile.LoadFromFile(aSourceFile);
      DestFile.LoadFromFile(aDestFile);
      Result := (SourceFile.Size = DestFile.Size) and
                CompareMem(SourceFile.Memory, DestFile.Memory, SourceFile.Size);
    finally
      DestFile.Free;
    end;
  finally
    SourceFile.Free;
  end;
end;
Vorschläge zur Verbesserung oder Optimierung des Codes sind gerne willkommen
Jeder kann ein Held werden und Leben retten!
Einfach beim NKR oder der DKMS als Stammzellenspender registrieren! Also: worauf wartest Du noch?
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#2

Re: Dateien byteweise vergleichen

  Alt 14. Mai 2010, 12:20
Eine byteweise Verarbeitung ist extrem langsam ... ließ ganze Blöcke aus und vergleiche diese z.B. mit CompareMemory deren Inhalt.

Jedesmal Seek aufzurufen ist auch unnötig, da Read den Positionszeiger schon verschiebt.

Read ohne Auswerten des Rückgabewertes zu verarbeiten ist nicht gut, da Lesefehler irgnoriert werden könnten. (verwende besser ReadBuffer oder werte das Result aus)

Ansonsten sollten schon einige Codes dafür in der DP existieren
(Einer ist z.B. in meinem Hier im Forum suchenSearchSameFiles verbaut)

Und eigentlich dürfte bestimmt auch Einer in der CodeLib zu finden sein.
[edit] jupp, ist gleich der 11. Eintrag in "Dateien / Laufwerke"
http://www.delphipraxis.net/internal...ct.php?t=60645

Die Fehlerbehandlung ist sehr schlecht, denn wann werden die Streams freigegeben, wenn eine Exception auftritt oder wenn die Dateigrößen unterschiedlich sind? (garnicht)
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.625 Beiträge
 
Delphi 12 Athens
 
#3

Re: Dateien byteweise vergleichen

  Alt 14. Mai 2010, 12:27
Ich hab mir mal erlaubt, eine bessere Fehlerbehandlung einzubringen und die ganzen "break" und "exit" zu eliminieren. Ob das ständige Seek notwendig ist, lass ich mal dahingestellt. BTW: Wäre es nicht schneller, TMemoryStreams zu verwenden und das mit CompareMemory abzuhandeln?
Delphi-Quellcode:
function ByteCompFiles(const aSourceFile, aDestFile: string): Boolean;
var
  SourceFile : TFileStream;
  DestFile: TFileStream;
  nCounter: Int64;
  ReadByteSource: Byte;
  ReadByteDest: Byte;
begin
  try
    Result := True;
    nCounter := 0;
    //Schreibzugriffe unterbinden, ansonsten wäre die ganze Aktion witzlos
    SourceFile := TFileStream.Create(aSourceFile, fmOpenRead or fmShareDenyWrite);
    try
      DestFile := TFileStream.Create(aDestFile, fmOpenRead or fmShareDenyWrite);
      try
        //Dateigröße ist unterschiedlich -> Abbruch
        Result := (SourceFile.Size = DestFile.Size);

        while Result and (nCounter < SourceFile.Size) do
        begin
          SourceFile.Seek(nCounter, soFromBeginning);
          SourceFile.Read(ReadByteSource, 1);

          DestFile.Seek(nCounter, soFromBeginning);
          DestFile.Read(ReadByteDest, 1);

          //Unterschied gefunden -> Abbruch
          Result := (ReadByteSource = ReadByteDest);

          Inc(nCounter);
          Sleep(10);
        end;
      finally
        DestFile.Free;
      end;
    finally
      SourceFile.Free;
    end;
  except
    Result := False
  end;
end;
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#4

Re: Dateien byteweise vergleichen

  Alt 14. Mai 2010, 12:30
Delphi-Quellcode:
try
  ...
except
  Result := False
end;
Dieses sollte besser ganz raus, denn bei einem Zugriffsfehler (z.B. fehlende Rechte) würde einfach nur FALSE ausgegeben, aber der Grund bleibt "geheim".
Außerdem könnte es ja dennoch sein, daß beide Dateien identisch sind, welches dann ntürlich ein falsches Ergebnis liefern würde.

die beiden kürzesten Quellcodes (nicht kürzeste Laufzeit) wären also:
Delphi-Quellcode:
function ByteCompFiles(const aSourceFile, aDestFile: string): Boolean;
var
  SourceFile, DestFile: TFileStream;
  Counter: Int64;
  ByteSource, ByteDest: Byte;
begin
  SourceFile := TFileStream.Create(aSourceFile, fmOpenRead or fmShareDenyWrite);
  try
    DestFile := TFileStream.Create(aDestFile, fmOpenRead or fmShareDenyWrite);
    try
      Result := SourceFile.Size = DestFile.Size;
      Counter := 0;
      while Result and (nCounter < SourceFile.Size) do
      begin
        SourceFile.ReadBuffer(ByteSource, 1);
        DestFile.ReadBuffer(ByteDest, 1);
        Result := ReadByteSource = ReadByteDest;
        Inc(Counter);
      end;
    finally
      DestFile.Free;
    end;
  finally
    SourceFile.Free;
  end;
end;

function ByteCompFiles(const aSourceFile, aDestFile: string): Boolean;
var
  SourceFile, DestFile: TFileStream;
  Counter: Int64;
  ByteSource, ByteDest: Byte;
begin
  SourceFile := TFileStream.Create(aSourceFile, fmOpenRead or fmShareDenyWrite);
  DestFile := nil;
  try
    DestFile := TFileStream.Create(aDestFile, fmOpenRead or fmShareDenyWrite);
    Result := SourceFile.Size = DestFile.Size;
    Counter := 0;
    while Result and (Counter < SourceFile.Size) do
    begin
      SourceFile.ReadBuffer(ByteSource, 1);
      DestFile.ReadBuffer(ByteDest, 1);
      Result := ReadByteSource = ReadByteDest;
      Inc(Counter);
    end;
  finally
    DestFile.Free;
    SourceFile.Free;
  end;
end;
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.625 Beiträge
 
Delphi 12 Athens
 
#5

Re: Dateien byteweise vergleichen

  Alt 14. Mai 2010, 12:31
Das überlass ich aber dem TE

[edit] Da würde ich die erste Variante aber vorziehen, da man dafür nicht unbedingt gewisse Kenntnisse über das Free braucht, um sie zu verstehen. [/edit]
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#6

Re: Dateien byteweise vergleichen

  Alt 14. Mai 2010, 13:06
Wenn die Funktion sowieso nur wahr oder falsch zurück gibt, kann man dann nicht einfach einen Hash nehmen?
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
mkinzler
(Moderator)

Registriert seit: 9. Dez 2005
Ort: Heilbronn
39.861 Beiträge
 
Delphi 11 Alexandria
 
#7

Re: Dateien byteweise vergleichen

  Alt 14. Mai 2010, 13:08
Wenn eine Wahscheinlichkeit reicht
Markus Kinzler
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#8

Re: Dateien byteweise vergleichen

  Alt 14. Mai 2010, 13:19
Zitat von mkinzler:
Wenn eine Wahscheinlichkeit reicht
Ein Hash wäre (vorallem wenn beide Dateien auf dem selben Datenträger liegen) wohl schneller, aber wie mkinzler sagen wollte "ein Hash ist nicht eindeutig".

Bei einem CRC32 gibt es schon bei Dateigrößen bis 5 Byte je Hash mindestens 256 Dateien mit diesem Hash.
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von HeikoAdams
HeikoAdams

Registriert seit: 12. Jul 2004
Ort: Oberfranken
661 Beiträge
 
FreePascal / Lazarus
 
#9

Re: Dateien byteweise vergleichen

  Alt 14. Mai 2010, 14:00
Ich habe meinen ersten Code auf die erste Version des Codes von himitsu aus seinem letzten Vorschlag aktualisiert und nebenbei noch nach Anregung von DeddyH auf TMemoryStreams umgebaut. Weitere Vorschläge sind erlaubt
Jeder kann ein Held werden und Leben retten!
Einfach beim NKR oder der DKMS als Stammzellenspender registrieren! Also: worauf wartest Du noch?
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#10

Re: Dateien byteweise vergleichen

  Alt 14. Mai 2010, 14:12
Wie gesagt, das langsame byteweise Lesen.
- Lesen über einen Puffer
- und der Einfachheit halber die Zählrichtung vom Counter umgedreht

Bedenke auch, daß bei TMemoryStream alles im RAM landet, welches bei größeren Dateien Probleme bereiten kann.
[add] Aber wenn eh schon alles im RAM liegt, dann kann man natürlich alles auf einmal vergleichen ... siehe nachfolgend Neutral General.

Delphi-Quellcode:
function ByteCompFiles(const aSourceFile, aDestFile: string): Boolean;
var
  SourceFile, DestFile: TFileStream;
  Counter: Int64;
  BufSize: Integer;
  SourceBuffer, DestBuffer: array[0..32767] of Byte;
begin
  SourceFile := TFileStream.Create(aSourceFile, fmOpenRead or fmShareDenyWrite);
  try
    DestFile := TFileStream.Create(aDestFile, fmOpenRead or fmShareDenyWrite);
    try
      Result := SourceFile.Size = DestFile.Size;
      Counter := SourceFile.Size;
      while Result and (Counter > 0) do
      begin
        if Counter >= SizeOf(SourceBuffer) then
          BufSize := SizeOf(SourceBuffer)
        else
          BufSize := Counter;
        SourceFile.ReadBuffer(SourceBuffer, BufSize);
        DestFile.ReadBuffer(DestBuffer, BufSize);
        Result := CompareMem(@SourceBuffer, @DestBuffer, BufSize);
        Dec(Counter, BufSize);
      end;
    finally
      DestFile.Free;
    end;
  finally
    SourceFile.Free;
  end;
end;
$2B or not $2B
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


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 06:08 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