Pregunta

necesito para comparar si dos TStream descendiente tienen el mismo contenido . El resultado sólo es interesante para mí es el booleano Sí / No.

Voy a código de una simple bucle comprobación de bytes a partir del byte de las corrientes de contenido.

Pero estoy curiosa para saber si hay una función ya existente. No he encontrado ninguna DelphiXE dentro o JCL / libs JVCL.

Por supuesto, las dos corrientes tienen el mismo tamaño!

¿Fue útil?

Solución

Exactamente, como Nickolay O. dijo que debe leer su secuencia en bloques y usar CompareMem. Aquí hay un ejemplo (incluyendo prueba de tamaño) ...

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;

Otros consejos

La IsIdenticalStreams Función Publicado por daemon_x es excelente - pero necesita un ajuste para que funcione correctamente. (Uwe Raabe captó el tema ya.) Es crítico que restablecer las posiciones de la corriente antes de comenzar el bucle - o este procedimiento probablemente devolver un VERDADERO incorrecto si las dos corrientes que ya se ha accedido, fuera de esta función.

Esta es la solución final que funciona todo el tiempo. Yo sólo cambió el nombre de la función para satisfacer mis convenciones de nomenclatura. Gracias daemon_x para la solución elegante.

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;

No hay tal función incorporada. Sólo hay una cosa que puedo recomendar -. No leer byte a byte, pero utilizando bloques de 16-64kbytes, que sería mucho más rápido

Las respuestas de user532231 y Mike están trabajando en el 99% de los casos, pero hay comprobaciones adicionales que se harán

Los descendientes de TStream puede ser casi cualquier cosa, por lo que no está garantizado que Stream.Read volverá misma cantidad de datos , incluso si las corrientes son de la misma longitud (descendiente corriente puede también descargar los datos, por lo puede devolver leido = 0 bytes, mientras espera para el próximo trozo). Corrientes pueden ser también de completelly diferentes medios de comunicación y flujo de error de lectura podrían producirse en una sola.

En el código de trabajo 100% todos debería convertirse en estas comprobaciones. He modificado la función de Mike.

Si se utiliza esta función, por ejemplo, para volver a escribir la corriente 2, si no idéntico, al TRANSMISIÓN 1, todos los errores deben ser revisados. Cuando resultado de la función es verdadera, todo es aceptable, pero si es falso, sería muy inteligente para comprobar si los flujos son realmente diferentes o simplemente ocurrió algún error.

Editado:. Añadido algunas comprobaciones adicionales, la función FilesAreIdentical basado en StreamsAreIdentical y ejemplo de uso

// 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;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top