質問

2つある場合は比較する必要があります Tストリーム 子孫 同じ内容です。私にとって唯一興味深い結果は、ブール値の Yes / No です。

コードを書いていきます 単純なループ ストリームのコンテンツをバイトごとにチェックします。

でも私 好奇心旺盛 既存の関数があるかどうかを知るため。DelphiXE または JCL/JVCL ライブラリ内には何も見つかりませんでした。

もちろん、2 つのストリームのサイズは同じです。

役に立ちましたか?

解決

まさに、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 によって投稿された関数は優れていますが、適切に動作するには 1 つの調整が必要です。(Uwe Raabe はすでに問題を発見しました。) ループを開始する前にストリームの位置をリセットすることが重要です - または、2 つのストリームがこの関数の外部ですでにアクセスされている場合、このプロシージャはおそらく誤った 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のブロックを使用して、それははるかに高速になります。

からの回答 ユーザー532231 そして マイク 99% のケースで機能しますが、 追加のチェックが必要!

TStream の子孫はほとんど何でもあり得るので、 Stream.Read が同じ量のデータを返すかどうかは保証されません, ストリームが同じ長さであっても (ストリームの子孫はデータをダウンロードすることもできるため、次のチャンクを待機している間に readed=0 バイトを返す可能性があります)。ストリームは完全に異なるメディア上に存在することもあり、一方のメディアでのみストリーム読み取りエラーが発生する可能性があります。

コードが 100% 機能するためには、これらすべてのチェックを行う必要があります。Mikeからの機能を修正しました。

たとえば、この関数を使用してストリーム 2 が Stream1 と同一でない場合に書き換える場合、すべてのエラーをチェックする必要があります。関数の結果が True の場合は何も問題ありませんが、False の場合は、ストリームが実際に異なるのか、それとも単にエラーが発生したのかを確認するのが非常に賢明です。

編集: いくつかの追加チェック、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;
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top