Get MD5 hash große Dateien in Python
Frage
Ich habe verwendet, hashlib (ersetzt md5 in Python 2.6/3.0) und es funktionierte gut, wenn ich eine Datei geöffnet und Ihr Inhalt in hashlib.md5()
Funktion.
Das problem ist mit sehr großen Dateien, deren Größe und mehr RAM-Größe.
Wie man den MD5-hash einer Datei, ohne das laden der gesamten Datei in den Speicher?
Lösung
Brechen Sie die Datei in 128-byte-Blöcken und führt Sie MD5 nacheinander mit update()
.
Dieses macht sich die Tatsache zunutze, dass die MD5-128-byte-digest-Blöcke.Im Grunde, wenn MD5 digest()
s die Datei, ist dies genau das, was Sie tut.
Wenn Sie sicherstellen, dass Sie den Speicher frei, die bei jeder iteration (D. H.nicht Lesen Sie die gesamte Datei in den Speicher), diese darf nicht mehr als 128 Byte Speicher.
Ein Beispiel ist das Lesen der Stücke wie folgt:
f = open(fileName)
while not endOfFile:
f.read(128)
Andere Tipps
Sie benötigen zum Lesen der Datei in Stücke von geeignet Größe:
def md5_for_file(f, block_size=2**20):
md5 = hashlib.md5()
while True:
data = f.read(block_size)
if not data:
break
md5.update(data)
return md5.digest()
HINWEIS:Stellen Sie sicher, dass Sie die Datei öffnen mit 'rb', um den öffnen - sonst erhalten Sie das falsche Ergebnis.
So zu tun, das ganze in eine Methode, verwenden Sie so etwas wie:
def generate_file_md5(rootdir, filename, blocksize=2**20):
m = hashlib.md5()
with open( os.path.join(rootdir, filename) , "rb" ) as f:
while True:
buf = f.read(blocksize)
if not buf:
break
m.update( buf )
return m.hexdigest()
Das update oben) wurde auf der Grundlage der Kommentare, die von Frerich Raabe - ich getestet und fand es richtig auf meine Python 2.7.2 windows-installation
I cross-checked-die Ergebnisse mit Hilfe der 'jacksum" - tool.
jacksum -a md5 <filename>
wenn Sie sich sorgen über mehr pythonic (no 'while True') Art und Weise des Lesens der Datei überprüfen Sie diesen code:
import hashlib
def checksum_md5(filename):
md5 = hashlib.md5()
with open(filename,'rb') as f:
for chunk in iter(lambda: f.read(8192), b''):
md5.update(chunk)
return md5.digest()
Beachten Sie, dass der iter() func Bedürfnisse ein leeres byte-Zeichenfolge für den zurückgegebenen iterator anhalten bei EOF, da read() liefert b" (nicht nur ").
Hier ist meine version von @Piotr Czapla Methode:
def md5sum(filename):
md5 = hashlib.md5()
with open(filename, 'rb') as f:
for chunk in iter(lambda: f.read(128 * md5.block_size), b''):
md5.update(chunk)
return md5.hexdigest()
Über mehrere Kommentar/Antworten in diesem thread, hier ist meine Lösung :
import hashlib
def md5_for_file(path, block_size=256*128, hr=False):
'''
Block size directly depends on the block size of your filesystem
to avoid performances issues
Here I have blocks of 4096 octets (Default NTFS)
'''
md5 = hashlib.md5()
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
md5.update(chunk)
if hr:
return md5.hexdigest()
return md5.digest()
- Dies ist "pythonic"
- Dies ist eine Funktion
- Es vermeidet implizite Werte:immer lieber expliziten lieben.
- Es ermöglicht (sehr wichtig) Leistungen Optimierungen
Und schließlich,
- Dies wurde von einer community, vielen Dank an alle für Eure Ratschläge/Ideen.
Ein Python 2/3 tragbare Lösung
Berechnung einer Prüfsumme (md5, sha1, etc.), öffnen Sie die Datei im binary-Modus, denn du wirst Summe Byte-Werte:
Werden py27/py3 portable, die Sie nutzen sollten die io
Pakete, wie diese:
import hashlib
import io
def md5sum(src):
md5 = hashlib.md5()
with io.open(src, mode="rb") as fd:
content = fd.read()
md5.update(content)
return md5
Wenn Ihre Dateien groß sind, bevorzugen Sie möglicherweise die Datei zu Lesen von Blöcken zu vermeiden, lagern den gesamten Inhalt einer Datei in den Speicher:
def md5sum(src, length=io.DEFAULT_BUFFER_SIZE):
md5 = hashlib.md5()
with io.open(src, mode="rb") as fd:
for chunk in iter(lambda: fd.read(length), b''):
md5.update(chunk)
return md5
Der trick hier ist die Verwendung der iter()
Funktion mit einem sentinel (dem leeren string).
Der iterator erstellt in diesem Fall rufen o [die lambda-Funktion] mit keine Argumente für jeden Anruf zu sein
next()
Methode;wenn der zurückgegebene Wert gleich sentinel,StopIteration
wird ausgelöst, andernfalls wird der Wert zurückgegeben werden.
Wenn Ihre Dateien wirklich big, müssen Sie möglicherweise auch Informationen über den Fortschritt anzeigen.Sie können tun, dass durch den Aufruf der callback-Funktion, die Drucke oder die Protokolle der Betrag der berechneten bytes:
def md5sum(src, callback, length=io.DEFAULT_BUFFER_SIZE):
calculated = 0
md5 = hashlib.md5()
with io.open(src, mode="rb") as fd:
for chunk in iter(lambda: fd.read(length), b''):
md5.update(chunk)
calculated += len(chunk)
callback(calculated)
return md5
Ein remix von Bastien Semene code, nehmen Hawkwing Kommentar über generische Hash-Funktion in Betracht...
def hash_for_file(path, algorithm=hashlib.algorithms[0], block_size=256*128, human_readable=True):
"""
Block size directly depends on the block size of your filesystem
to avoid performances issues
Here I have blocks of 4096 octets (Default NTFS)
Linux Ext4 block size
sudo tune2fs -l /dev/sda5 | grep -i 'block size'
> Block size: 4096
Input:
path: a path
algorithm: an algorithm in hashlib.algorithms
ATM: ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')
block_size: a multiple of 128 corresponding to the block size of your filesystem
human_readable: switch between digest() or hexdigest() output, default hexdigest()
Output:
hash
"""
if algorithm not in hashlib.algorithms:
raise NameError('The algorithm "{algorithm}" you specified is '
'not a member of "hashlib.algorithms"'.format(algorithm=algorithm))
hash_algo = hashlib.new(algorithm) # According to hashlib documentation using new()
# will be slower then calling using named
# constructors, ex.: hashlib.md5()
with open(path, 'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
hash_algo.update(chunk)
if human_readable:
file_hash = hash_algo.hexdigest()
else:
file_hash = hash_algo.digest()
return file_hash
u kann nicht erhalten es ist die md5-ohne Lesen Sie den gesamten Inhalt.aber u verwenden können update Funktion zum Lesen der Dateien-content block-block.
m.update(a);m.update(b) ist äquivalent zu m.update(a+b)
Ich denke, der folgende code ist mehr pythonic:
from hashlib import md5
def get_md5(fname):
m = md5()
with open(fname, 'rb') as fp:
for chunk in fp:
m.update(chunk)
return m.hexdigest()
Die Umsetzung der akzeptierten Antwort für Django:
import hashlib
from django.db import models
class MyModel(models.Model):
file = models.FileField() # any field based on django.core.files.File
def get_hash(self):
hash = hashlib.md5()
for chunk in self.file.chunks(chunk_size=8192):
hash.update(chunk)
return hash.hexdigest()
Ich mag es nicht Schleifen.Basierend auf dem @Nathan Feger:
md5 = hashlib.md5()
with open(filename, 'rb') as f:
functools.reduce(lambda _, c: md5.update(c), iter(lambda: f.read(md5.block_size * 128), b''), None)
md5.hexdigest()
import hashlib,re
opened = open('/home/parrot/pass.txt','r')
opened = open.readlines()
for i in opened:
strip1 = i.strip('\n')
hash_object = hashlib.md5(strip1.encode())
hash2 = hash_object.hexdigest()
print hash2
Ich bin mir nicht sicher, dass es nicht ein bisschen zu viel Getue hier in der Nähe.Vor kurzem hatte ich Probleme mit md5 und Dateien als blobs in MySQL so experimentierte ich mit verschiedenen Dateigrößen und unkompliziert in der Python-Ansatz, nämlich:
FileHash=hashlib.md5(FileData).hexdigest()
Ich konnte erkennen, keine merkliche performance-Unterschied mit einer Reihe von Datei-Größen von 2 kB auf 20 MB und daher kein Grund für 'Stück' der Vermischung.Jedenfalls, wenn Linux auf der Festplatte, wird es wahrscheinlich tun, es mindestens genauso gut wie die durchschnittlichen Programmierer, die Fähigkeit zu halten es tun.Als es geschah, war das problem nichts zu tun mit md5.Wenn Sie MySQL verwenden, vergessen Sie nicht die md5() und sha1 () - Funktionen bereits vorhanden.