Ich habe hashlib verwendet (das md5 in Python 2.6 / 3.0 ersetzt) und es hat gut funktioniert, wenn ich eine Datei geöffnet und ihren Inhalt in hashlib.md5()
Funktion gesetzt habe.
Das Problem ist bei sehr großen Dateien, dass ihre Größe die RAM-Größe überschreiten kann.
Wie erhalte ich den MD5-Hash einer Datei, ohne die gesamte Datei in den Speicher zu laden?
Antworten:
Teilen Sie die Datei in 8192-Byte-Blöcke (oder ein anderes Vielfaches von 128 Byte) auf und führen Sie sie nacheinander mit MD5 ein
update()
.Dies nutzt die Tatsache aus, dass MD5 128-Byte-Digest-Blöcke hat (8192 ist 128 × 64). Da Sie nicht die gesamte Datei in den Speicher einlesen, werden nicht viel mehr als 8192 Byte Speicher benötigt.
In Python 3.8+ können Sie dies tun
quelle
hashlib.blake2b
anstelle von verwendenmd5
. Im Gegensatz zu MD5 ist BLAKE2 sicher und noch schneller.Sie müssen die Datei in Blöcken geeigneter Größe lesen:
HINWEIS: Stellen Sie sicher, dass Sie Ihre Datei mit dem 'rb' zum Öffnen öffnen - andernfalls erhalten Sie das falsche Ergebnis.
Um das Ganze in einer Methode zu erledigen, verwenden Sie Folgendes:
Das obige Update basiert auf den Kommentaren von Frerich Raabe - und ich habe dies getestet und festgestellt, dass es in meiner Python 2.7.2-Windows-Installation korrekt ist
Ich habe die Ergebnisse mit dem Tool 'jacksum' überprüft.
http://www.jonelo.de/java/jacksum/
quelle
rb
an dieopen
Funktion.hexdigest
anstelle vondigest
erzeugt einen hexadezimalen Hash, der wie die meisten Beispiele für Hashes "aussieht".if len(data) < block_size: break
?open
immer ein neues Dateihandle mit der Position am Anfang der Datei (es sei denn, Sie öffnen eine Datei zum Anhängen).Unten habe ich Vorschläge aus Kommentaren aufgenommen. Vielen Dank al!
Python <3.7
Python 3.8 und höher
ursprünglicher Beitrag
Wenn Sie mehr pythonische (kein 'while True') Methoden zum Lesen der Datei bevorzugen, überprüfen Sie diesen Code:
Beachten Sie, dass die Funktion iter () eine leere Bytezeichenfolge benötigt, damit der zurückgegebene Iterator bei EOF anhält, da read () b '' (nicht nur '') zurückgibt.
quelle
128*md5.block_size
anstelle von8192
.md5.block_size
.b''
Syntax war neu für mich. Erklärt hier .Hier ist meine Version der Methode von @Piotr Czapla:
quelle
Mit mehreren Kommentaren / Antworten in diesem Thread ist hier meine Lösung:
Und schlussendlich,
- Dies wurde von einer Community erstellt. Vielen Dank für Ihre Ratschläge / Ideen.
quelle
Eine tragbare Python 2/3-Lösung
Um eine Prüfsumme (md5, sha1 usw.) zu berechnen, müssen Sie die Datei im Binärmodus öffnen, da Sie Bytewerte summieren:
Um py27 / py3 portabel zu sein, sollten Sie die
io
Pakete wie folgt verwenden :Wenn Ihre Dateien groß sind, ziehen Sie es möglicherweise vor, die Datei in Blöcken zu lesen, um zu vermeiden, dass der gesamte Dateiinhalt im Speicher gespeichert wird:
Der Trick hier besteht darin, die
iter()
Funktion mit einem Sentinel (der leeren Zeichenfolge) zu verwenden.Wenn Ihre Dateien wirklich groß sind, müssen Sie möglicherweise auch Fortschrittsinformationen anzeigen. Sie können dies tun, indem Sie eine Rückruffunktion aufrufen, die die Anzahl der berechneten Bytes druckt oder protokolliert:
quelle
Ein Remix von Bastien Semene-Code, der Hawkwing-Kommentare zur generischen Hashing-Funktion berücksichtigt ...
quelle
Sie können es nicht md5 bekommen, ohne den vollständigen Inhalt zu lesen. Sie können jedoch die Aktualisierungsfunktion verwenden, um den Dateiinhalt Block für Block zu lesen.
m.update (a); m.update (b) entspricht m.update (a + b)
quelle
Ich denke, der folgende Code ist pythonischer:
quelle
Implementierung der akzeptierten Antwort für Django:
quelle
Ich mag keine Loops. Basierend auf @Nathan Feger:
quelle
hashlib
API mit dem Rest von Python nicht wirklich gut funktioniert. Nehmen wir zum Beispiel,shutil.copyfileobj
was genau nicht funktioniert. Meine nächste Idee warfold
(akareduce
), die iterables zu einzelnen Objekten zusammenfaltet. Wie zB ein Hash.hashlib
bietet keine Operatoren, was dies etwas umständlich macht. Trotzdem falteten sich hier iterable.quelle
Ich bin mir nicht sicher, ob es hier nicht zu viel Aufhebens gibt. Ich hatte kürzlich Probleme mit md5 und Dateien, die als Blobs auf MySQL gespeichert waren, also experimentierte ich mit verschiedenen Dateigrößen und dem einfachen Python-Ansatz, nämlich:
Ich konnte keinen merklichen Leistungsunterschied bei einem Bereich von Dateigrößen von 2 KB bis 20 MB feststellen und musste daher das Hashing nicht "aufteilen". Wenn Linux auf die Festplatte gehen muss, wird es dies wahrscheinlich mindestens genauso gut tun wie die Fähigkeit des durchschnittlichen Programmierers, dies zu verhindern. Das Problem hatte übrigens nichts mit md5 zu tun. Wenn Sie MySQL verwenden, vergessen Sie nicht die bereits vorhandenen Funktionen md5 () und sha1 ().
quelle