Delphi函数比较两个T流的内容?
题
我需要比较如果两个 T流后代的有相同的内容。 对我来说,唯一有趣的结果是布尔是/否。
我要代码的简单的循环后字节流内容的校验字节。
但我的好奇即可知道是否有一个已经存在的功能。我还没有发现任何内部DelphiXE或JCL / JVCL库。
当然,这两个流具有相同的尺寸!
解决方案
准确,作为Nickolay O.说你应该读块的数据流,并使用CompareMem。下面是(包括大小试验)...
的示例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;
其他提示
的 IsIdenticalStreams 强>张贴由daemon_x功能是优异的 - 但需要一个调整到正常工作。 (乌韦·拉贝抓住了问题了。)您在启动循环的前重置流的位置,是的的关键 - 或此过程可能会返回TRUE不正确,如果两个流被这个功能之外已经访问。
这是,每次工作的最终溶液。我刚刚改名的功能,以满足我的命名约定。感谢您daemon_x了优雅的解决方案。
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;
有没有这样的内置函数。只有一件事我可以推荐 - 读不字节到字节,但使用16-64kbytes块,这将是更快
这答案的 user532231 和麦克在99%的情况下工作,但也有提出的额外的检查!
T流的后人几乎可以是任何东西,所以它不能保证Stream.Read将返回的数据相同量,即使流的长度是相同的(流后代也可以下载数据,所以可以返回readed = 0字节,同时等待下一个块)。流还可以是上completelly不同介质和流读取可能发生上错误只是一个。
有关100%的工作码的所有这些检查应进行。我从麦克修改的功能。
如果该功能是用来,例如,如果不相同的流1重写流2,所有错误,应检查。如果函数结果为真,寄托都是好的,但如果是假的,那将是非常聪明的,以检查是否流实际上是不同的,或只是一些错误发生。的
<强>被修改:增加了一些附加的检查,基于StreamsAreIdentical和使用例FilesAreIdentical功能 强>
// 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;