Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Neuen Beitrag zur Code-Library hinzufügen (https://www.delphipraxis.net/33-neuen-beitrag-zur-code-library-hinzufuegen/)
-   -   Delphi Dateien byteweise vergleichen (https://www.delphipraxis.net/151352-dateien-byteweise-vergleichen.html)

HeikoAdams 14. Mai 2010 11:08


Dateien byteweise vergleichen
 
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 :)

himitsu 14. Mai 2010 11:20

Re: Dateien byteweise vergleichen
 
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. :gruebel:
[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)

DeddyH 14. Mai 2010 11:27

Re: Dateien byteweise vergleichen
 
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;

himitsu 14. Mai 2010 11:30

Re: Dateien byteweise vergleichen
 
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;

DeddyH 14. Mai 2010 11:31

Re: Dateien byteweise vergleichen
 
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]

Luckie 14. Mai 2010 12:06

Re: Dateien byteweise vergleichen
 
Wenn die Funktion sowieso nur wahr oder falsch zurück gibt, kann man dann nicht einfach einen Hash nehmen?

mkinzler 14. Mai 2010 12:08

Re: Dateien byteweise vergleichen
 
Wenn eine Wahscheinlichkeit reicht

himitsu 14. Mai 2010 12:19

Re: Dateien byteweise vergleichen
 
Zitat:

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.

HeikoAdams 14. Mai 2010 13:00

Re: Dateien byteweise vergleichen
 
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 :wink:

himitsu 14. Mai 2010 13:12

Re: Dateien byteweise vergleichen
 
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;


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:09 Uhr.
Seite 1 von 3  1 23      

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