Si vous avez 1 000 000 de fichiers source, vous pensez qu'ils sont tous identiques et vous voulez les comparer. Quelle est la méthode actuelle de jeûne pour comparer ces fichiers? Supposons qu'il s'agisse de fichiers Java et que la plate-forme sur laquelle la comparaison est effectuée n'est pas importante. Cksum me fait pleurer. Quand je veux dire identique, je veux dire TOUT identique.
Mise à jour: / Je sais comment générer des sommes de contrôle. le diff est risible ... je veux de la vitesse.
Mise à jour: Ne restez pas bloqué sur le fait qu'il s'agisse de fichiers sources. Imaginez, par exemple, que vous ayez réalisé un million d'exécutions d'un programme à sortie très régulée. Vous voulez prouver que les 1 000 000 versions de la sortie sont identiques.
Mise à jour: lire le nombre de blocs plutôt que d'octets? Jeter immédiatement ceux-ci? Est-ce plus rapide que de trouver le nombre d'octets?
Mise à jour: Est-ce que CELA est différent du moyen le plus rapide de comparer deux fichiers?
J'opterais pour quelque chose comme l'approche adoptée par le programme cmp
: ouvrir deux fichiers (par exemple, fichier 1 et fichier 2), lire un bloc de chaque fichier et les comparer octet par octet. Si elles correspondent, lisez le prochain bloc de chaque, comparez-les, octet par octet, etc. Si vous arrivez à la fin des deux fichiers sans détecter de différences, recherchez le début du fichier 1, fermez le fichier 2 et ouvrez le fichier 3. à sa place, et répétez jusqu'à ce que tous les fichiers soient vérifiés. Je ne pense pas qu'il soit possible d'éviter de lire tous les octets de tous les fichiers s'ils sont en réalité tous identiques, mais je pense que cette approche est (ou est proche de) le moyen le plus rapide de détecter toute différence pouvant exister.
OP Modification : Commentaire important soulevé par Mark Bessey
"Une autre optimisation évidente, si les fichiers doivent être essentiellement identiques et s'ils sont relativement petits, consiste à garder l'un des fichiers entièrement en mémoire. Cela évite d'essayer de lire deux fichiers à la fois."
La plupart des gens dans leurs réponses ignorent le fait que les fichiers doivent être comparés à plusieurs reprises. Ainsi, les sommes de contrôle sont plus rapides car la somme de contrôle est calculée une fois et stockée en mémoire (au lieu de lire les fichiers de manière séquentielle n fois).
En supposant que les fichiers soient identiques (il semble que ce soit le cas), traiter avec des sommes de contrôle/hachages est une perte de temps - il est probable qu'ils seront identiques et vous devrez lisez les fichiers pour obtenir la preuve finale (je suppose également que puisque vous voulez "prouver ... qu'ils sont identiques", il ne suffit pas de les hacher avec la même valeur).
Si tel est le cas, je pense que la solution proposée par David est assez proche de ce que vous devez faire. Quelques solutions possibles pour optimiser la comparaison, avec un niveau de complexité croissant:
Mise à jour: Ne restez pas coincé sur le fait qu'il s'agisse de fichiers source. Imaginez, par exemple, que vous ayez réalisé un million d'exécutions d'un programme à sortie très régulée. Vous voulez prouver que les 1 000 000 versions de la sortie sont identiques.
si vous avez le contrôle sur la sortie, demandez au programme créant les fichiers/la sortie de créer un md5 à la volée et de l'intégrer au flux de fichier ou de sortie ou même de diriger la sortie via un programme créant le md5 en cours de route et le stockant les données en quelque sorte, le point est de faire les calculs lorsque les octets sont déjà en mémoire.
comme vous l'avez dit, vérifiez la taille des fichiers, puis effectuez une comparaison octet par octet simple sur des fichiers de même taille. Je ne vois pas en quoi une division binaire ou un calcul md5 est supérieur à une simple. Si vous comparez, vous devrez toucher chaque octet pour prouver l’égalité de la manière voulue afin de réduire la quantité de calcul nécessaire par octet et d’obtenir la capacité de couper dès que vous trouvez une mauvaise correspondance.
le calcul de md5 serait utile si vous envisagez de les comparer ultérieurement à de nouvelles sorties, mais revenez à mon premier point de calcul du md5 dès que possible
Il existe un certain nombre de programmes qui comparent un ensemble de fichiers en général pour en trouver des identiques. FDUPES est un bon exemple: Link . Un million de fichiers ne devrait pas être un problème, selon la nature exacte de l'entrée. Je pense que FDUPES nécessite Linux, mais il existe d'autres programmes similaires pour d'autres plateformes.
J'ai moi-même essayé d'écrire un programme plus rapide, mais à l'exception de cas particuliers, FDUPES était plus rapide.
Quoi qu'il en soit, l'idée générale est de commencer par vérifier la taille des fichiers. Les fichiers ayant des tailles différentes ne peuvent pas être égaux, il vous suffit donc d'examiner des groupes de fichiers de même taille. Cela devient alors plus compliqué si vous souhaitez obtenir des performances optimales: si les fichiers sont probablement différents, comparez-en de petites parties, dans l’espoir de trouver les différences plus tôt, afin que vous n'ayez pas à les lire. Cependant, si les fichiers sont probablement identiques, il peut être plus rapide de lire chaque fichier pour calculer une somme de contrôle, car vous pouvez alors lire séquentiellement à partir du disque au lieu de basculer entre deux fichiers ou plus. (Cela suppose des disques normaux, donc SSD: s peut être différent.)
Dans mes repères, lorsque je tentais de créer un programme plus rapide, il s’avérait plus rapide de lire d’abord chaque fichier pour calculer une somme de contrôle, puis, si les sommes de contrôle étaient égales, de comparer les fichiers directement en lisant des blocs à partir de chaque fichier, que de lire les blocs en alternance sans les calculs de somme de contrôle précédents! Il s'est avéré que lors du calcul des sommes de contrôle, Linux a mis les deux fichiers en mémoire cache dans la mémoire principale, en les lisant de manière séquentielle, et les deuxièmes lectures ont ensuite été très rapides. Lors du démarrage avec des lectures en alternance, les fichiers n'étaient pas lus (physiquement) séquentiellement.
MODIFIER:
Certaines personnes ont exprimé leur surprise et même leur doute qu'il pourrait être plus rapide de lire les fichiers deux fois que de les lire une seule fois. Peut-être que je n'ai pas réussi à expliquer très clairement ce que je faisais. Je parle de préchargement de cache, afin d’avoir les fichiers dans le cache de disque lorsqu’ils y accèderont plus tard de manière lente sur le lecteur de disque physique. Ici est une page Web sur laquelle j'ai essayé d'expliquer plus en détail, avec des images, du code C et des mesures.
Cependant, cela a (au mieux) une pertinence marginale par rapport à la question initiale.
Eh bien, l'algorithme le plus optimal dépend du nombre de fichiers en double.
En supposant que certains soient identiques, mais la plupart sont différents et les fichiers sont volumineux.
Filtrez ceux qui ne sont évidemment pas les mêmes en utilisant une simple vérification de la longueur du fichier.
Choisir des octets aléatoires dans le fichier, calculer un hachage et comparer (minimiser les recherches sur le disque)
Suivez cela avec un fichier complet SHA1.
Je ne pense pas que le hachage sera plus rapide que les comparaisons octet par octet. La comparaison octet par octet peut être optimisée un peu en ajoutant la lecture et la comparaison des octets, mais plusieurs sections du fichier peuvent également être comparées dans des threads parallèles. Ce serait aller quelque chose comme ça:
Ou tout simplement exécuter un cmp (ou l'équivalent pour votre système d'exploitation) en parallèle. Cela pourrait être écrit facilement et vous bénéficiez toujours du parallélisme.
Utiliser cksum
n’est pas aussi fiable que d’utiliser quelque chose comme md5sum
. Mais je choisirais une fiabilité maximale, ce qui signifie une comparaison octet par octet en utilisant cmp
.
Vous devez lire chaque octet dans les deux fichiers pour toutes les méthodes de vérification afin que vous puissiez aussi bien choisir celle qui est la plus fiable.
Dans un premier temps, vous pouvez vérifier la liste des répertoires pour voir si les tailles sont différentes. C'est un moyen rapide d'obtenir des commentaires plus rapides pour différents fichiers.
Je voudrais courir quelque chose comme ça
find -name \*.Java -print0 | xargs -0 md5sum | sort
puis voir quels fichiers ont des sommes différentes MD5. Cela regroupera les fichiers par somme de contrôle.
Vous pouvez remplacer md5sum qui sha1sum ou même rmd160 si vous le souhaitez.
Commencez par comparer les longueurs de fichiers de tous les millions. Si vous avez un moyen économique de le faire, commencez par les fichiers les plus volumineux. S'ils réussissent tous, comparez chaque fichier à l'aide d'un modèle de division binaire; cela échouera plus rapidement sur les fichiers similaires mais pas les mêmes. Pour plus d'informations sur cette méthode de comparaison, voir Méthode Knuth-Morris-Pratt .
À mon avis, il s'agit d'une opération de système de fichiers. Alors d’abord, choisissez votre système de fichiers avec soin. Ensuite, dédupliquer. Ensuite, comparez les inodes. Comme:
% find / -inum "$(ls -di "./test.file" | grep -E '^[0-9]*')"
<list of identical files provided in a few seconds to a minute>
au-delà de la comparaison, synchronisez deux dossiers, super rapide! nous l'utilisons tout le temps, tous les jours.
Utilisez le concept de Bloom Filter. Une explication simple: http://crzyjcky.com/2013/01/03/the-magical-bloom-filter/
Cela vous donne un temps constant de comparaison. Cependant, cette méthode ne peut pas être utilisée seule. Apache Cassandra et HBase utilisent cette technique en interne.
Il indique essentiellement que les fichiers ne sont pas identiques de manière très rapide. Si le fichier est identique, vous devez effectuer une nouvelle vérification en utilisant une méthode fiable.
Si vous souhaitez comparer des fichiers un par un, utilisez ExamDiff.
Le hachage MD5 serait plus rapide que la comparaison, mais plus lent qu'un contrôle CRC normal. Vous devez déterminer le type de fiabilité que vous souhaitez en comparaison.
Je viens d'écrire une application c # qui fait quelque chose de similaire à ce que vous voulez. Voici ce que fait mon code.
Lisez toutes les tailles de chaque fichier dans une liste ou un tableau.
Utilisez une boucle for pour vérifier si l’une de ces tailles est la même. Si elles ont la même taille, comparez un octet d’un fichier à un octet de l’autre fichier. Si les deux octets sont identiques, passez à l'octet suivant. Si une différence est trouvée, indiquez que les fichiers sont différents.
Si la fin des deux fichiers est atteinte et que les deux derniers octets sont identiques, les fichiers doivent être identiques.
J'ai essayé de comparer les hachages MD5 de fichiers plutôt que de passer d'octet en octet, et j'ai constaté que les fichiers identiques sont souvent omis avec cette méthode, mais elle est nettement plus rapide.
Pourquoi réinventer la roue? Que diriez-vous d'une application tierce? Certes, il n’a pas d’API, mais je n’imagine pas que vous vous mettez souvent dans cette situation. J'aime cette application doublekiller il suffit de faire une sauvegarde avant de commencer. :) C'est rapide et gratuit!