Bonjour !
J'aurais besoin d'une fonction qui permette de savoir si deux fichiers quelconques sont identiques (même avec des noms différents).
Comment feriez-vous ça ?
Bonjour !
J'aurais besoin d'une fonction qui permette de savoir si deux fichiers quelconques sont identiques (même avec des noms différents).
Comment feriez-vous ça ?
Bonjour,
Plusieurs moyens :
- le plus simpliste
- Comparer les tailles
- Si tailles égales
- comparer byte à byte
- plus élaboré
- Comparer les tailles
- Si tailles égales
- calculer les hash (CRC ou md5 .... au choix)
![]()
Merci droggo pour la réponse.
Donc à la limite on pourrait faire comme ça ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 type Octet = Byte; TFichier = file of Octet; function CompareFichiers(const aNomFichier1, aNomFichier2: string): Boolean; var fichier1, fichier2: TFichier; octet1, octet2: Octet; begin {$I-} AssignFile(fichier1, aNomFichier1); result := IOResult = 0; if not result then Exit; AssignFile(fichier2, aNomFichier2); result := IOResult = 0; if not result then Exit; {$I+} try Reset(fichier1); Reset(fichier2); while result and (not EOF(fichier1)) and (not EOF(fichier2)) do begin Read(fichier1, octet1); Read(fichier2, octet2); result := octet1 = octet2; end; if result then result := EOF(fichier1) and EOF(fichier2); finally CloseFile(fichier1); CloseFile(fichier2); end; end; begin WriteLn(CompareFichiers('image.jpg', 'image - Copie.jpg')); end.
Bonjour,
Je ne suis pas allé plus loin que ça, car si c'est ok pour fichier1 et que ça échoue pour fichier2, tu ne libères pas fichier1.
D'accord, c'est une variable locale, mais c'est un principe de base de tout nettoyer, et de ne pas compter sur le système pour le faire.
Et un peu plus loin, il faudrait aussi vérifier les reset
ET contrôler les tailles des fichiers AVANT de commencer la comparaison octet à octet, qui est inutile si les tailles sont différentes.
![]()
Merci droggo.
J'ai revu ma copie en essayant de prendre en compte tes remarques.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 type Octet = Byte; TFichier = file of Octet; function CompareFichiers(const aNomFichier1, aNomFichier2: string): Boolean; var fichier1, fichier2: TFichier; octet1, octet2: Octet; tailleFichier1, tailleFichier2: Int64; begin AssignFile(fichier1, aNomFichier1); AssignFile(fichier2, aNomFichier2); {$I-} Reset(fichier1); result := IOResult = 0; if result then begin Reset(fichier2); result := IOResult = 0; if not result then CloseFile(fichier1); end; {$I+} if not result then Exit; tailleFichier1 := FileSize(fichier1); tailleFichier2 := FileSize(fichier2); result := tailleFichier1 = tailleFichier2; if not result then begin CloseFile(fichier1); CloseFile(fichier2); Exit; end; while result and not EOF(fichier1) do begin Read(fichier1, octet1); Read(fichier2, octet2); result := octet1 = octet2; end; CloseFile(fichier1); CloseFile(fichier2); end; begin WriteLn(CompareFichiers('image.jpg', 'image - Copie.jpg')); end.
Une variante (beaucoup plus rapide) utilisant BlockRead au lieu de Read :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 type Octet = Byte; TFichier = file of Octet; function CompareFichiers(const aNomFichier1, aNomFichier2: string): Boolean; const TAILLE_TAMPON = 256; var fichier1, fichier2: TFichier; tailleFichier1, tailleFichier2: Int64; tampon1, tampon2: array[0..TAILLE_TAMPON - 1] of Octet; octetsLus, iOctet: Word; begin AssignFile(fichier1, aNomFichier1); AssignFile(fichier2, aNomFichier2); {$I-} Reset(fichier1, 1); result := IOResult = 0; if result then begin Reset(fichier2, 1); result := IOResult = 0; if not result then CloseFile(fichier1); end; {$I+} if not result then Exit; tailleFichier1 := FileSize(fichier1); tailleFichier2 := FileSize(fichier2); result := tailleFichier1 = tailleFichier2; if not result then begin CloseFile(fichier1); CloseFile(fichier2); Exit; end; repeat BlockRead(fichier1, tampon1, TAILLE_TAMPON, octetsLus); BlockRead(fichier2, tampon2, TAILLE_TAMPON, octetsLus); iOctet := 0; while result and (iOctet < octetsLus) do begin result := tampon1[iOctet] = tampon2[iOctet]; Inc(iOctet); end; until octetsLus < TAILLE_TAMPON; CloseFile(fichier1); CloseFile(fichier2); end; begin WriteLn(CompareFichiers('image.jpg', 'image - Copie.jpg')); end.
Bonjour,
Oui, BlockRead a toujours été la bonne méthode pour ce genre de travail, je m'en étais entre autres servi pour mon implémentation de calculs de hash (CRC, md*, ...)
ps : ne me demande pas mon code pour ces fonctions, c'est mon employeur de l'époque qui en est propriétaire.
![]()
salut
utiise les TMemorystream c'est pratique
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 function CompareFiles(aBaseFileName,aCompareFileName : String): boolean; begin Result := FALSE; //Instantiate the two memory streams FBaseStream := TMemoryStream.Create; FCompareStream := TMemoryStream.Create; try //Load both files into their respective streams... FBaseStream.LoadFromFile(aBaseFileName); FCompareStream.LoadFromFile(aCompareFileName); //...and compare them Result := (FBaseStream.Size = FCompareStream.Size) and CompareMem(FBaseStream.Memory, FCompareStream.Memory, FBaseStream.Size); finally //Tidy up FBaseStream.Free; FCompareStream.Free; FBaseStream := Nil; FCompareStream := Nil; end; end;
Merci pour vos réponses. Je crois que nous avons plus ou moins fait le tour du sujet.
Il y a cependant encore une chose sur laquelle j'aimerais vous questionner, ce sont les "calculs de hash" dont parlait droggo. En un mot, qu'est-ce que c'est ? Et en quoi cela peut-il se substituer (avantageusement ou non) à une comparaison octet par octet ?![]()
Hello
Pour des questions de performance, j'essaierai de lire des blocs de taille fixe (par exemple, 16k ou 32k, mais ça dépend de la taille du fichier et donc du nombre de blocs à traiter par la suite) puis de calculer un checksum sur ces blocs puis de les comparer.
Les checksum/hash permettent d'avoir une sorte de signature d'un volume de données. Si les signatures sont égales, les blocs de données sont égaux. Tu peux regarder md5 pour cela, il devrait exister des implémentations Pascal...
Merci pour ta réponse. Ah oui, tiens, il existe une unité md5 livrée avec FPC.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 uses md5; var hash1, hash2: string; begin hash1 := MD5Print(MD5File('image1.jpg')); hash2 := MD5Print(MD5File('image2.jpg')); WriteLn(hash1); WriteLn(hash2); WriteLn(hash1 = hash2); ReadLn; end.
Bonjour,
N'y aurait-il pas une erreur fondamentale dans ce prédicat ?
Il me semble qu'au contraire c'est la différence des signatures qui indique, à coup sûr, que les données sont différentes.
L'égalité des signatures ne constituant qu'une probabilité d'égalité des données.
Par ailleurs, en termes de performances, l'emploi de clés (CRC, MD5, etc.) pour comparer deux fichiers ne seraient intéressante que si les clés étaient pré-calculées et embarquées dans les fichiers de donnée. Sinon le calcul des clés nécessitera le parcours intégral des deux fichiers ce qui prendra toujours plus de temps que la comparaison simple laquelle peut cesser dès la première différence trouvée.
Merci pour vos réponses.
J'ai rassemblé dans une unité les solutions proposées (plus une autre que j'ai trouvée ailleurs) et écrit un programme de test. Les temps d'exécution varient tellement d'une fois à l'autre qu'il est impossible d'en tirer une conclusion. Tout ce que j'ai remarqué, c'est que la taille des blocs lus influe beaucoup sur le temps d'exécution.
J'ai retouché la fonction que j'avais postée plus haut, parce que je me suis aperçu que je n'avais pas suffisamment pris en compte le cas de deux fichiers différents mais de taille identique.
Bonsoir,
petite modif en bas du fichier test.pas, afin de lui faire accepter deux paramètres sur la ligne de commande, ce qui est bien sympathique à l'usage
mise en commentaire des deux lignes de constantes, et ajout de 3 lignes :
Pas touché au reste, et ma foi, ça fonctionne.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 {const FICHIER1 = 'fichier1.zip'; // **** à modifier **** FICHIER2 = 'fichier2.zip'; // **** à modifier **** } var i: integer; FICHIER1,FICHIER2: string; // ajout begin FICHIER1 := paramstr(1); // ajout FICHIER2 := paramstr(2); // ajout
Bien joué, Roland !
![]()
Bonjour à tous,
Une discussion intéressante. Je trouve que la remarque de DomDA91 est pertinente. En résumé, il y a un dilemme entre faire les choses de façon sûre mais lente et faire les choses efficacement avec des risques d'erreurs mais de façon plus rapide.
L'algorithme MD5 a une page wiki qui lui est dédiée : https://fr.wikipedia.org/wiki/MD5
Il n'est pas considéré comme sûr, d'autres algorithmes (qui ne seront jamais totalement sûrs puisqu'ils utilisent le hashage, deux objets de couleur rouge ne sont pas forcément identiques par exemple) ont été suggérés à sa place.
Du peu que je comprends, sans être expert.
Partager