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?

War es hilfreich?

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>

http://www.jonelo.de/java/jacksum/

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top