Question

Je dois comparer si deux TStream descendant ont le même contenu . Le seul résultat intéressant pour moi est le booléen Oui / Non.

Je vais coder un simple boucle vérification octet après octet

de la teneur en eau.

Mais je suis curieux pour savoir s'il y a une fonction déjà existante. Je n'ai pas trouvé dans libs DelphiXE ou JCL / JVCL.

Bien sûr, les deux cours d'eau ont la même taille!

Était-ce utile?

La solution

Exactement, comme Nickolay O. dit que vous devriez lire votre flux en blocs et utiliser CompareMem. Voici un exemple (y compris le test de taille) ...

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;

Autres conseils

La fonction IsIdenticalStreams Publié par daemon_x est excellent - mais a besoin d'un ajustement pour fonctionner correctement. (Uwe Raabe a pris la question déjà.) Il est essentiel que vous réinitialiser les positions de flux avant de commencer la boucle - ou cette procédure retournerez probablement un VRAI incorrect si les deux cours d'eau étaient déjà accessibles en dehors de cette fonction.

Ceci est la solution finale qui fonctionne à chaque fois. Je viens retitré la fonction en fonction de mes conventions de nommage. Merci daemon_x pour la solution élégante.

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;

Il n'y a pas une telle fonction intégrée. Une seule chose que je peux recommander -. Pas lu octet par octet, mais en utilisant des blocs de 16-64kbytes, ce serait beaucoup plus rapide

Les réponses de user532231 et Mike travaillent dans 99% des cas, mais il y a contrôles supplémentaires à effectuer

Les descendants de TStream peuvent être presque tout, si il est pas garanti que Stream.Read retourne même quantité de données , même si les flux sont de la même longueur (descendant de flux peut également télécharger des données, donc peut retourner readed = 0 octets, en attendant morceau suivant). Les flux peuvent être également sur des supports différents et completelly erreur de lecture de flux peuvent se produire sur un seul.

Pour le code de 100% tous ces contrôles devraient être effectués. J'ai modifié la fonction de Mike.

Si cette fonction est utilisée par exemple pour réécrire le flux 2 sinon identique à Stream1, il faut vérifier toutes les erreurs. Lorsque résultat de la fonction est vrai, everthing est ok, mais si elle est fausse, il serait très intelligent pour vérifier si Streams sont réellement différents ou tout simplement une erreur est survenue.

Modifié:. Ajout des contrôles supplémentaires, la fonction FilesAreIdentical basée sur StreamsAreIdentical et exemple d'utilisation

// 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;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top