![]() |
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:
Vorschläge zur Verbesserung oder Optimierung des Codes sind gerne willkommen :)
{
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; |
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 ![]() Und eigentlich dürfte bestimmt auch Einer in der CodeLib zu finden sein. :gruebel: [edit] jupp, ist gleich der 11. Eintrag in "Dateien / Laufwerke" ![]() Die Fehlerbehandlung ist sehr schlecht, denn wann werden die Streams freigegeben, wenn eine Exception auftritt oder wenn die Dateigrößen unterschiedlich sind? (garnicht) |
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; |
Re: Dateien byteweise vergleichen
Delphi-Quellcode:
Dieses sollte besser ganz raus, denn bei einem Zugriffsfehler (z.B. fehlende Rechte) würde einfach nur FALSE ausgegeben, aber der Grund bleibt "geheim".
try
... except Result := False end; 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; |
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] |
Re: Dateien byteweise vergleichen
Wenn die Funktion sowieso nur wahr oder falsch zurück gibt, kann man dann nicht einfach einen Hash nehmen?
|
Re: Dateien byteweise vergleichen
Wenn eine Wahscheinlichkeit reicht
|
Re: Dateien byteweise vergleichen
Zitat:
Bei einem CRC32 gibt es schon bei Dateigrößen bis 5 Byte je Hash mindestens 256 Dateien mit diesem Hash. |
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:
|
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 11:08 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz