web-dev-qa-db-de.com

Was ist der schnellste Weg, um zu überprüfen, ob Dateien identisch sind?

Wenn Sie 1.000.000 Quelldateien haben, vermuten Sie, dass sie alle gleich sind, und Sie möchten sie vergleichen. Wie werden diese Dateien derzeit verglichen? Angenommen, es handelt sich um Java-Dateien, und die Plattform, auf der der Vergleich durchgeführt wird, ist nicht wichtig. Cksum bringt mich zum Weinen. Wenn ich identisch meine, meine ich ALLE identisch.

Update: Ich weiß über die Generierung von Prüfsummen. diff ist lächerlich ... ich will Geschwindigkeit.

Update: Bleib nicht bei der Tatsache hängen, dass es sich um Quelldateien handelt. Stellen Sie sich zum Beispiel vor, Sie hätten eine Million Durchläufe eines Programms mit sehr regulierter Ausgabe gemacht. Sie möchten beweisen, dass alle 1.000.000 Versionen der Ausgabe gleich sind.

Update: Lesen Sie die Anzahl der Blöcke anstelle von Bytes? Die sofort rausschmeißen? Ist das schneller als die Anzahl der Bytes zu finden?

Update: Ist das anders als der schnellste Weg, um zwei Dateien zu vergleichen?

31
ojblass

Ich würde mich für etwas wie den Ansatz des cmp-Programms entscheiden: Öffnen Sie zwei Dateien (zB Datei 1 und Datei 2), lesen Sie einen Block aus und vergleichen Sie sie byteweise. Wenn sie übereinstimmen, lesen Sie den nächsten Block von jedem, vergleichen Sie sie byteweise usw. Wenn Sie das Ende beider Dateien erreichen, ohne Unterschiede festzustellen, gehen Sie zum Anfang von Datei 1, schließen Sie Datei 2 und öffnen Sie Datei 3 und wiederholen Sie es, bis Sie alle Dateien überprüft haben. Ich glaube nicht, dass es eine Möglichkeit gibt, das Lesen aller Bytes aller Dateien zu vermeiden, wenn sie tatsächlich alle identisch sind, aber ich denke, dieser Ansatz ist (oder liegt nahe) am schnellsten, um mögliche Unterschiede festzustellen.

OP Modification : Wichtiger Kommentar von Mark Bessey angehoben

"Eine weitere offensichtliche Optimierung, wenn erwartet wird, dass die Dateien größtenteils identisch sind und wenn sie relativ klein sind, bleibt eine der Dateien vollständig im Speicher. Das reduziert den Thrash-Versuch, zwei Dateien gleichzeitig zu lesen."

23
David Z

Die meisten Leute in ihren Antworten ignorieren die Tatsache, dass die Dateien wiederholt verglichen werden müssen. Daher sind die Prüfsummen schneller, da die Prüfsumme einmal berechnet und gespeichert wird (anstatt die Dateien n-mal nacheinander zu lesen).

14
Doug Bennett

Angenommen, die Erwartung ist, dass die Dateien die gleichen sein werden (es klingt wie das Szenario), dann ist der Umgang mit Prüfsummen/Hashes eine Zeitverschwendung - es ist wahrscheinlich, dass sie gleich sind und Sie sich Lesen Sie die Dateien, um den endgültigen Beweis zu erhalten (ich gehe außerdem davon aus, dass Sie, wenn Sie "beweisen wollen, dass sie gleich sind", dass es nicht gut genug ist, sie auf den gleichen Wert zu bringen).

Wenn das der Fall ist, denke ich, dass die von David vorgeschlagene Lösung ziemlich nahe an dem liegt, was Sie tun müssten. Ein paar Dinge, die getan werden könnten, um den Vergleich in zunehmendem Maß an Komplexität zu optimieren:

  • prüfen Sie vor dem Vergleich, ob die Dateigrößen gleich sind
  • verwenden Sie das schnellste memcmp (), das Sie können (Wörter anstelle von Bytes vergleichen - die meisten C-Laufzeiten sollten dies bereits tun)
  • verwenden Sie mehrere Threads, um die Speicherblockvergleiche durchzuführen (bis zu der Anzahl der auf dem System verfügbaren Prozessoren, das Durchlaufen des Threads würde dazu führen, dass Ihr Thread sich gegenseitig bekämpft).
  • verwenden Sie überlappende/asynchrone E/A, um die E/A-Kanäle so stark wie möglich zu halten, aber auch ein sorgfältiges Profil, so dass Sie so wenig wie möglich zwischen den Dateien wechseln (wenn die Dateien auf mehrere verschiedene Festplatten und E/A-Ports verteilt sind) desto besser)
7
Michael Burr

Update: Bleiben Sie nicht auf der Tatsache, dass es sich um Quelldateien handelt. Stellen Sie sich zum Beispiel vor, Sie hätten eine Million Durchläufe eines Programms mit sehr regulierter Ausgabe genommen. Sie möchten nachweisen, dass alle 1.000.000 Versionen der Ausgabe gleich sind.

wenn Sie die Kontrolle über die Ausgabe haben, muss das Programm, das die Dateien/Ausgaben erstellt, eine md5 im Handumdrehen erstellen und in die Datei oder den Ausgabestream einbetten oder sogar die Ausgabe durch ein Programm leiten, das die md5 auf dem Weg erstellt und entlang der Seite speichert die Daten irgendwie, Punkt ist, die Berechnungen durchzuführen, wenn die Bytes bereits im Speicher sind.

wenn dies nicht möglich ist, überprüfen Sie die Dateigrößen, und überprüfen Sie die Dateigrößen und vergleichen Sie sie mit den gleichgroßen Dateien. Ich sehe nicht, wie eine binäre Division oder eine MD5-Berechnung besser als eine Gerade ist Im Vergleich dazu müssen Sie jedes Byte berühren, um die Gleichheit in jeder Weise zu beweisen, in der Sie es schneiden, so dass Sie ebenso den Rechenaufwand pro Byte reduzieren können und die Möglichkeit erhalten, das Signal abzulegen, sobald Sie eine falsche Übereinstimmung feststellen.

die md5-Berechnung wäre nützlich, wenn Sie diese später erneut mit neuen Ausgaben vergleichen möchten, aber im Grunde zurück zu meinem ersten Punkt, die md5 so schnell wie möglich zu berechnen

6
mark

Es gibt eine Reihe von Programmen, die einen Satz Dateien im Allgemeinen vergleichen, um identische zu finden. FDUPES ist ein guter: Link . Eine Million Dateien sollten je nach der Art der Eingabe kein Problem sein. Ich denke, dass FDUPES Linux benötigt, es gibt aber auch andere Programme für andere Plattformen.

Ich habe selbst versucht, ein schnelleres Programm zu schreiben, aber abgesehen von Sonderfällen war FDUPES schneller.

Die allgemeine Idee ist jedoch, zunächst die Größe der Dateien zu überprüfen. Dateien mit unterschiedlichen Größen können nicht gleich sein. Sie müssen also nur Gruppen von Dateien mit derselben Größe betrachten. Wenn Sie eine optimale Leistung wünschen, wird es komplizierter: Wenn sich die Dateien wahrscheinlich unterscheiden, sollten Sie kleine Teile der Dateien in der Hoffnung vergleichen, Unterschiede frühzeitig zu finden, damit Sie die übrigen Dateien nicht lesen müssen. Wenn die Dateien wahrscheinlich identisch sind, kann es jedoch schneller sein, jede Datei zu lesen, um eine Prüfsumme zu berechnen, da Sie dann sequentiell von der Festplatte lesen können, anstatt zwischen zwei oder mehr Dateien hin und her zu springen. (Dies setzt normale Festplatten voraus, daher können sich SSDs unterscheiden.)

Beim Versuch, ein schnelleres Programm zu erstellen, stellte sich heraus (etwas zu meiner Überraschung), dass es schneller war, zuerst jede Datei durchzulesen, um eine Prüfsumme zu berechnen, und dann, wenn die Prüfsummen gleich sind, die Dateien direkt zu vergleichen, indem die Blöcke abwechselnd gelesen werden von jeder Datei, als nur Blöcke abwechselnd ohne die vorherigen Checksummenberechnungen zu lesen! Es stellte sich heraus, dass Linux bei der Berechnung der Prüfsummen beide Dateien im Hauptspeicher zwischengespeichert hat, wobei jede Datei nacheinander gelesen wurde, und die zweiten Lesevorgänge dann sehr schnell waren. Beim Starten mit abwechselnden Lesevorgängen wurden die Dateien nicht (physisch) sequentiell gelesen.

BEARBEITEN:

Einige Leute äußerten überraschend und zweifelten sogar daran, dass es schneller sein könnte, die Dateien zweimal zu lesen, als nur einmal. Vielleicht konnte ich nicht klar erklären, was ich tat. Ich spreche vom Cache-Pre-Loading, um die Dateien im Festplatten-Cache zu speichern, wenn später auf sie auf eine Art und Weise zugegriffen wird, die auf dem physischen Festplattenlaufwerk langsam ist. Hier ist eine Webseite, auf der ich versucht habe, ausführlicher zu erklären, mit Bildern, C-Code und Maßen.

Dies hat jedoch (im besten Fall) eine geringe Relevanz für die ursprüngliche Frage.

Der optimale Algorithmus hängt von der Anzahl der doppelten Dateien ab. 

Angenommen, einige sind gleich, aber die meisten sind unterschiedlich und die Dateien sind groß. 

Filtern Sie diejenigen heraus, die offensichtlich nicht gleich sind, indem Sie die Länge der Datei einfach überprüfen. 

Wählen Sie zufällige Bytes aus der Datei, berechnen Sie einen Hash und vergleichen Sie ihn (Minimierung der Laufwerkssuche). 

Folgen Sie dem mit einer vollständigen Datei SHA1. 

2
Sam Saffron

Ich glaube nicht, dass Hashing-Vergleiche Byte für Byte schneller sein werden. Der Byte-für-Byte-Vergleich kann durch Pipelining des Lesens und Vergleichens der Bytes ein wenig optimiert werden. Außerdem können mehrere Abschnitte der Datei in parallelen Threads verglichen werden. Es würde so etwas gehen:

  • Prüfen Sie, ob die Dateigrößen unterschiedlich sind
  • Lesen Sie die Blöcke der Dateien asynchron in den Speicher
  • Handle sie an Worker-Threads, um die Vergleiche durchzuführen

Oder führen Sie einfach ein CMP (oder das Äquivalent für Ihr Betriebssystem) parallel aus. Dies könnte leicht in Skripts geschrieben werden und Sie profitieren immer noch von Parallelität.

1
BeWarned

Die Verwendung von cksum ist nicht so zuverlässig wie die Verwendung von etwas wie md5sum. Ich würde mich jedoch für maximale Zuverlässigkeit entscheiden, was einen byteweisen Vergleich mit cmp bedeutet.

Sie müssen jedes Byte in beiden Dateien für alle Prüfmethoden lesen, sodass Sie sich auch für das zuverlässigste entscheiden können.

Als ersten Durchlauf können Sie die Verzeichnisliste überprüfen, um zu sehen, ob die Größen unterschiedlich sind. Auf diese Weise können Sie schnelles Feedback für verschiedene Dateien erhalten.

1
paxdiablo

Ich würde so etwas laufen lassen

find -name \*.Java -print0 | xargs -0 md5sum | sort

dann sehen Sie, welche Dateien unterschiedliche MD5-Summen haben. Dadurch werden die Dateien nach Prüfsumme gruppiert.

Sie können md5sum, das sha1sum oder sogar rmd160 ersetzen, wenn Sie möchten.

1
Blair Zajac

Vergleichen Sie zunächst die Dateilängen aller Millionen. Wenn Sie dies kostengünstig tun, beginnen Sie mit den größten Dateien. Wenn sie alle bestehen, vergleichen Sie jede Datei mit einem binären Teilungsmuster. Dies wird bei Dateien, die ähnlich, jedoch nicht identisch sind, schneller fehlschlagen. Informationen zu dieser Vergleichsmethode finden Sie unter Knuth-Morris-Pratt-Methode .

0
Peter Wone

Meiner Meinung nach handelt es sich um eine Dateisystemoperation. Wählen Sie zuerst Ihr Dateisystem sorgfältig aus. Als nächstes deduplizieren. Dann vergleichen Sie Inodes. Mögen:

% find / -inum "$(ls -di "./test.file" | grep -E '^[0-9]*')"
<list of identical files provided in a few seconds to a minute>
0
mikeserv

unvergleichlich, zwei Ordner synchronisieren, superschnell! wir benutzen es die ganze Zeit, jeden Tag.

0
bo.

Verwenden Sie das Konzept des Bloom-Filters. Eine einfache Erklärung hier: http://crzyjcky.com/2013/01/03/the-magical-bloom-filter/

Es gibt Ihnen eine konstante Zeit des Vergleichs. Diese Methode kann jedoch nicht alleine angewendet werden. Apache Cassandra und HBase verwenden diese Technik intern.

Im Prinzip wird u gesagt, dass die Dateien nicht sehr schnell identisch sind. Wenn die Datei identisch ist, müssen Sie eine weitere Kontrollrunde mit zuverlässiger Methode durchführen.

0
janetsmith

Wenn Sie Dateien einzeln vergleichen möchten, verwenden Sie ExamDiff.

0
md27

MD5-Hash wäre schneller als der Vergleich, aber langsamer als eine normale CRC-Prüfung. Sie müssen herausfinden, welche Zuverlässigkeit Sie im Vergleich wünschen.

0
sangupta

Ich habe gerade eine c # app geschrieben, die etwas ähnliches tut, was Sie wollen. Was mein Code macht, ist das.

Lesen Sie alle Größen der einzelnen Dateien in eine Liste oder ein Array ein.

Verwenden Sie eine for-Schleife, um zu überprüfen, ob eine dieser Größen identisch ist. Wenn sie dieselbe Größe haben, vergleichen Sie ein Byte einer Datei mit einem Byte der anderen Datei. Wenn die zwei Bytes gleich sind, fahren Sie mit dem nächsten Byte fort. Wenn ein Unterschied gefunden wird, geben Sie zurück, dass sich die Dateien unterscheiden. 

Wenn das Ende beider Dateien erreicht ist und die letzten zwei Bytes gleich sind, müssen die Dateien identisch sein.

Ich habe mit dem Vergleich von MD5-Hashes von Dateien experimentiert, anstatt Byte für Byte durchzugehen, und ich habe festgestellt, dass identische Dateien mit dieser Methode oft übersehen werden, jedoch ist sie wesentlich schneller. 

0
Ryan

Warum das Rad neu erfinden? Wie wäre es mit einer Drittanbieter-App? Zugegeben, es hat keine APIs, aber ich kann mir nicht vorstellen, dass Sie sich oft in diese Situation begeben. Ich mag diese App doublekiller mache einfach ein Backup, bevor du anfängst. :) Es ist schnell und kostenlos!

0
NitroxDM