J'ai besoin de comparer si deux Je vais coder une "forte> boucle simple forte> check-octet après octet le contenu des flux. P>
Mais je suis Bien sûr, les deux ruisseaux ont la même taille! P>
4 Réponses :
Il n'y a pas de fonctionnalité de ce type. Une seule chose que je peux recommander - lire pas les octets à octet, mais utiliser des blocs de 16-64kbytes, ce serait beaucoup plus rapide. P>
ouais, de grands blocs avec des appels à compareremem pourront cela faire
Ok, merci pour cette première réponse et les astuces sur les gros blocs. J'accepterai la réponse de Daemon_X car il y a le code complet avec l'utilisation du comparatif ().
Exactement, comme Nickolay O. a déclaré que vous devriez lire votre flux en blocs et utiliser un comparatif. 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;
Peut-être que cela aide lorsque vous définissez les deux positions de flux à 0 avant de commencer votre boucle.
Ou charger les flux entiers dans 2 Mémoramays et nourrir ceux à comparermem.
@Uwe Raabe - +1, vous êtes totalement droit, @Remko - +1, vous avez probablement raison aussi, j'espère que ce comparatif quitte immédiatement quand il trouve la différence d'octet
Je n'aime pas TMemoryStream car c'est une catastrophe pour les fichiers volumineux en raison de sa nécessité d'avoir un bloc de mémoire contigu. Cela ira peut-être à DCC64 mais jusque-là, cela mérite d'éviter. Ce code ne fonctionnera pas car il représente des flux dont la taille est inférieure à block_size parce que vous comparez du bruit de pile aléatoire.
@Daemon_x CompeMemem est en effet court-circuit. Mais alors quoi, avec un bloc de 4k, vous ne remarqueriez pas la différence.
@Daemon_X La solution simple pour cela est de noter la valeur de retour de l'appel à ttream.Read comme bytesread et passez min (bytesdread, block_size) au comparatif.
@David Heffernan - Oui, tu étais plus rapide :)
@David Heffernan: TMemoryStream fonctionne bien tant que vous prévenez la mémoire appelant la mémoire SETSIZE Si vous savez quelle taille il sera à l'avance. Quoi qu'il en soit, pour comparer deux flux, je ne les chargerais pas complètement en mémoire, mieux de commencer à charger, comparer et arrêtez-vous au premier décalage, en particulier pour les gros flux sur disque (ou à d'autres sources «lentes», c'est-à-dire un champ de base de données).
@David Heffernan - J'ai écrit ce morceau de code à la volée, donc si vous avez du temps, modifiez-le et postez-le à votre réponse :)
@Daemon_x c'est mieux! Et je ne sais pas ce que je continuais avec min (buffer_length, block_size) code> car cela est toujours égal à buffer_length. D'Oh!
@Idsandon non, cela ne fonctionne pas bien! Vous pouvez soit avoir un flux> 2 Go dans lequel il échoue certainement. Ou alternativement, il peut ne pas y avoir un bloc assez important d'espace d'adressage contigu disponible disponible. Cela se produit bien avant d'arriver à 2 Go sous la plupart des modèles d'utilisation normale.
Les C'est la solution finale qui fonctionne à chaque fois. Je viens de renommé la fonction pour convenir à mes conventions de nommage. Merci Daemon_x pour la solution élégante. P> 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;
réponses de Descendants de Tstream peut être presque n'importe quoi, donc Pour 100% de code de travail, toutes ces vérifications doivent être effectuées. J'ai modifié la fonction de Mike. P> Si cette fonction est utilisée par exemple pour réécrire le flux 2 s'il n'est pas identique à Stream1, toutes les erreurs doivent être vérifiées. Lorsque le résultat de la fonction est vrai, tout cela est correct, mais s'il est faux, il serait très intelligent de vérifier si des flux sont en réalité différentes ou simplement une erreur survenue. EM> P> Edité: a ajouté des contrôles supplémentaires, FichiersAdentifier Fonction basé sur l'exemple StreamSareDidydyDidydyDidyDidydyDidydyDidyDidySical et d'utilisation. EM> PR> // 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;
+1 pour la remarque intéressante. THX pour répondre à une question assez ancienne, je suis toujours émerveillé de voir comment [logiciels] les gens sont tellement consacrés à partager et à améliorer et à échanger continuellement ... je n'ai jamais vu cela ailleurs :)
Trident: Il suffit de faire du monde un meilleur endroit;)
Je laisserais certainement l'exception à être jetée. Si quelque chose ne va pas lors de la lecture et que vous «mangerez ce problème» et de retourner juste un booléen, personne ne sera jamais en mesure de déterminer quel était le problème. Et, il n'est pas nécessaire de comparer ablocksize code> de mémoire, mais juste
tampon1dreaded code> ou
tampon2dreaded code> (ils seront égaux).
TLAMA: La seule exception possible ici est "Exception de lecture de flux", c'est donc sûr de retourner AERROR: = true sur faux résultat. Personnellement, je préfère ne pas déshabiller l'exécution du programme, mais c'est une question de goût et d'opinion: p aussi je préfère ne pas encoder statiquement la taille de la mémoire tampon (Construct Const en fonction du paramètre Const) et j'ai déplacé des tampons de la pile vers le tas. Encore une fois, il s'agit d'un goût des programmeurs et de la quantité de flexibilité qu'il veut. À propos de CompeMemem Vous avez absolument raison, j'ai changé en tampon1ired depuis les deux sont les mêmes!
Vous avez raison que c'est une question de goût ... Quoi qu'il en soit, utilisez @ code> Char suivi du nom de l'utilisateur (il déclenchera l'autosuggestion pendant que vous commencerez à taper) pour répondre à une personne à notifier A propos d'un nouveau commentaire (comme par exemple
@Tlama code> me informerait). Je n'ai pas utilisé cela puisque vous êtes le propriétaire du poste et vous êtes donc toujours notifié ainsi que le propriétaire de la question. Merci et bienvenue dans le débordement de la pile!
@David serait-ce que cela fonctionnerait sur un ruisseau inférieur à 4096 en taille? (tampon1dreaded <> ablockSize) code> Que se passe-t-il?
@Merlinw. Oui, cela fonctionnerait même sur un flux de taille 0.;) Il ne compare que la quantité de la quantité de lecture de manière acualement lue, et si elle n'est pas la même taille, elle sort avant que si (tampon1dreaded <> tampon2dread) code >, et cette partie
ou ((tampon1dreeded <> ablocksize) et (astresam1.position
@Merlinw. En fait, tout en travaillant aujourd'hui sur un autre projet, j'ai découvert que le comparatif n'est pas aussi sûr que la longueur ou le déplacement, ce qui fonctionne normalement sur une matrice dynamique de longueur zéro (NIL). La fonction s'écraserait si une personne, pour une raison d'étrange, choisirait une taille de bloc de 0 (et pourrait même entraîner une boucle sans fin, car 0 octets seraient lus tout en s'attendant à atteindre la fin du flux). J'ai donc ajouté plus de chèques et exemple d'utilisation avec une fonction fichiersAdentiperie, à l'aide de StreamSareDidyDidyDidyDidyStical;)
@Trident - Je pense que l'âge de la question est hors de propos. Nous sommes ici pour enseigner / apprendre :)