Delphi-Funktion zu vergleichen Inhalt von zwei TStream?
Frage
ich brauche, wenn zwei miteinander vergleichen TStream Nachkomme haben den gleichen Inhalt . Das einzige interessantes Ergebnis ist für mich die boolean Ja / Nein.
Ich bin, um Code geht eine einfache Schleife Überprüfung Byte für Byte den Inhalt des Streams.
Aber ich bin neugierig wissen, ob es eine bereits vorhandene Funktion ist. Ich habe nicht gefunden jede innerhalb DelphiXE oder JCL / JVCL Libs.
Natürlich haben die beiden Ströme die gleiche Größe!
Lösung
Genau, wie Nickolay O. sagte Sie Ihren Strom in Blöcke lesen und CompareMem verwenden. Hier ist ein Beispiel (einschließlich Größe Test) ...
function IsIdenticalStreams(Source, Destination: TStream): boolean;
const Block_Size = 4096;
var Buffer_1: array[0..Block_Size-1] of byte;
Buffer_2: array[0..Block_Size-1] of byte;
Buffer_Length: integer;
begin
Result := False;
if Source.Size <> Destination.Size then
Exit;
while Source.Position < Source.Size do
begin
Buffer_Length := Source.Read(Buffer_1, Block_Size);
Destination.Read(Buffer_2, Block_Size);
if not CompareMem(@Buffer_1, @Buffer_2, Buffer_Length) then
Exit;
end;
Result := True;
end;
Andere Tipps
Die IsIdenticalStreams Funktion von daemon_x geschrieben ist ausgezeichnet - aber muss man Anpassung richtig an die Arbeit. (Uwe Raabe fing das Problem bereits.) Es ist wichtig, dass Sie die Stream-Positionen zurückgesetzt, bevor die Schleife Anfahr - oder dieses Verfahren wird wahrscheinlich eine falsche TRUE zurück, wenn die beiden Ströme bereits außerhalb dieser Funktion abgerufen wurden.
Dies ist die letzte Lösung, die jedes Mal funktioniert. Ich umbenannt nur die Funktion meiner Namenskonventionen zu entsprechen. Danke daemon_x für die elegante Lösung.
function StreamsAreIdentical(Stream1, Stream2: TStream): boolean;
const
Block_Size = 4096;
var
Buffer_1: array[0..Block_Size-1] of byte;
Buffer_2: array[0..Block_Size-1] of byte;
Buffer_Length: integer;
begin
Result := False;
if Stream1.Size <> Stream2.Size then exit;
// These two added lines are critical for proper operation
Stream1.Position := 0;
Stream2.Position := 0;
while Stream1.Position < Stream1.Size do
begin
Buffer_Length := Stream1.Read(Buffer_1, Block_Size);
Stream2.Read(Buffer_2, Block_Size);
if not CompareMem(@Buffer_1, @Buffer_2, Buffer_Length) then exit;
end;
Result := True;
end;
Es gibt keine integrierte Funktion. Nur eine Sache, die ich empfehlen kann -. Las nicht Byte-zu-Byte, sondern Blöcke von 16-64kbytes verwenden, die viel schneller wäre
Antworten von user532231 und Mike sind in 99% der Fälle zu arbeiten, aber es gibt zusätzliche Kontrollen vorgenommen werden
Nachkommen von TStream kann fast alles sein, so ist es nicht garantiert, dass Stream.Read gleiche Datenmenge zurück , auch wenn Ströme sind von gleicher Länge (Strom Nachkomme auch Daten herunterladen können, so kann return readed = 0 Byte, während für die nächste Brocken wartet). Streams können auch auf sein completelly verschiedenen Medien und Stream-Lesefehler auftreten, auf konnte nur eine.
Für 100% Arbeits Code alle sollten diese Kontrollen durchgeführt werden. Ich veränderte die Funktion von Mike.
Wenn diese Funktion zum Beispiel verwendet wird Strom neu zu schreiben 2, wenn nicht identisch mit Stream1 sollte alle Fehler überprüft werden. Wenn die Funktion Ergebnis Wahr ist, Everthing ist in Ordnung, aber wenn es falsch ist, wäre es sehr klug sein, zu überprüfen, ob Streams tatsächlich unterschiedlich sind oder nur einige Fehler ist aufgetreten.
Edited:. hinzugefügt einige zusätzliche Kontrollen, FilesAreIdentical Funktion basierend auf StreamsAreIdentical und Verwendungsbeispiel
// Usage example
var lError: Integer;
...
if FilesAreIdentical(lError, 'file1.ext', 'file2.ext')
then Memo1.Lines.Append('Files are identical.')
else case lError of
0: Memo1.Lines.Append('Files are NOT identical!');
1: Memo1.Lines.Append('Files opened, stream read exception raised!');
2: Memo1.Lines.Append('File does not exist!');
3: Memo1.Lines.Append('File open exception raised!');
end; // case
...
// StreamAreIdentical
function StreamsAreIdentical(var aError: Integer;
const aStream1, aStream2: TStream;
const aBlockSize: Integer = 4096): Boolean;
var
lBuffer1: array of byte;
lBuffer2: array of byte;
lBuffer1Readed,
lBuffer2Readed,
lBlockSize: integer;
begin
Result:=False;
aError:=0;
try
if aStream1.Size <> aStream2.Size
then Exit;
aStream1.Position:=0;
aStream2.Position:=0;
if aBlockSize>0
then lBlockSize:=aBlockSize
else lBlockSize:=4096;
SetLength(lBuffer1, lBlockSize);
SetLength(lBuffer2, lBlockSize);
lBuffer1Readed:=1; // just for entering while
while (lBuffer1Readed > 0) and (aStream1.Position < aStream1.Size) do
begin
lBuffer1Readed := aStream1.Read(lBuffer1[0], lBlockSize);
lBuffer2Readed := aStream2.Read(lBuffer2[0], lBlockSize);
if (lBuffer1Readed <> lBuffer2Readed) or ((lBuffer1Readed <> lBlockSize) and (aStream1.Position < aStream1.Size))
then Exit;
if not CompareMem(@lBuffer1[0], @lBuffer2[0], lBuffer1Readed)
then Exit;
end; // while
Result:=True;
except
aError:=1; // stream read exception
end;
end;
// FilesAreIdentical using function StreamsAreIdentical
function FilesAreIdentical(var aError: Integer;
const aFileName1, aFileName2: String;
const aBlockSize: Integer = 4096): Boolean;
var lFileStream1,
lFilestream2: TFileStream;
begin
Result:=False;
try
if not (FileExists(aFileName1) and FileExists(aFileName2))
then begin
aError:=2; // file not found
Exit;
end;
lFileStream1:=nil;
lFileStream2:=nil;
try
lFileStream1:=TfileStream.Create(aFileName1, fmOpenRead or fmShareDenyNone);
lFileStream2:=TFileStream.Create(aFileName2, fmOpenRead or fmShareDenyNone);
result:=StreamsAreIdentical(aError, lFileStream1, lFileStream2, aBlockSize);
finally
if lFileStream2<>nil
then lFileStream2.Free;
if lFileStream1<>nil
then lFileStream1.Free;
end; // finally
except
aError:=3; // file open exception
end; // except
end;