Question

Je l'ai utilisé hashlib (qui remplace md5 en Python 2.6 / 3.0) et il a bien fonctionné si j'ai ouvert un fichier et de mettre son contenu dans hashlib.md5() fonction .

Le problème est avec des fichiers très grands que leur taille pourrait dépasser la taille de la RAM.

Comment obtenir le hachage MD5 d'un fichier sans charger le fichier entier à la mémoire?

Était-ce utile?

La solution

Briser le fichier en morceaux de 128 octets et les nourrir à l'aide MD5 consécutivement update().

profite du fait que MD5 a 128 octets digest blocs. En gros, quand MD5 digest()s le fichier, c'est exactement ce qu'il fait.

Si vous assurez-vous de libérer la mémoire à chaque itération (à savoir lire le fichier entier à la mémoire), cela doit prendre plus de 128 octets de mémoire.

Un exemple est de lire les morceaux comme ceci:

f = open(fileName)
while not endOfFile:
    f.read(128)

Autres conseils

Vous devez lire le fichier en morceaux de taille approprié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()

REMARQUE: Assurez-vous que vous ouvrez votre fichier avec le « rb » à l'air libre - sinon vous obtiendrez le résultat erroné

.

Donc, pour faire le tout en une seule méthode - utiliser quelque chose comme:

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()

La mise à jour ci-dessus était basé sur les commentaires fournis par Frerich Raabe - et je l'ai testé cela et trouvé être correct sur mon windows Python 2.7.2 l'installation

vérifiées par recoupement les résultats en utilisant l'outil « jacksum ».

jacksum -a md5 <filename>

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

si vous vous souciez plus pythonique (pas « while True ») façon de lire le fichier vérifier ce 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()

Notez que l'iter () func a besoin d'une chaîne d'octets vide pour l'itérateur retourné à arrêter à EOF, depuis lecture () retourne b « » (et pas seulement « »).

Voici ma version de la méthode de @Piotr Czapla:

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()

Utilisation de plusieurs commentaires / réponses sur ce sujet, voici ma solution:

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()
  • Ceci est "pythonique"
  • Ceci est une fonction
  • Il évite les valeurs implicites: toujours préférer les explicites
  • .
  • Il permet des optimisations de performances (très importantes)

Et enfin,

-. Cela a été construit par une communauté, merci à tous pour vos conseils / idées

un python solution portable 2/3

Pour calculer une somme de contrôle (md5, SHA1, etc.), vous devez ouvrir le fichier en mode binaire, car vous additionnez les valeurs octets:

Pour être PY27 / PY3 portable, vous devez utiliser les paquets de io, comme ceci:

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

Si vos fichiers sont grands, vous pouvez préférer lire le fichier par morceaux pour éviter de stocker tout le contenu du fichier dans la mémoire:

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

L'astuce est d'utiliser la fonction iter() avec < em> sentinelle (chaîne vide).

  

Le iterator créé dans ce cas appellera o [la fonction lambda] sans arguments pour chaque appel à sa méthode next(); si la valeur retournée est égale à sentinelle, StopIteration sera élevé, sinon la valeur sera renvoyée.

Si vos fichiers sont vraiment grand, vous pouvez également besoin d'afficher des informations de progression. Vous pouvez le faire en appelant une fonction de rappel qui imprime ou enregistre la quantité d'octets calculés:

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

Un remix du Code Bastien Semene qui prennent un commentaire Hawkwing sur la fonction de hachage générique en considération ...

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 ne peut pas l'obtenir est md5 sans contenu Lire l'article complet. mais u peut utiliser mise à jour fonction pour lire les fichiers bloc de contenu par bloc.
m.update (a); m.update (b) est équivalent à m.update (a + b)

Je pense que le code suivant est plus pythonique:

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()

La mise en œuvre de la réponse acceptée pour 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()

Je n'aime pas les boucles. Sur la base de @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

Je ne suis pas sûr qu'il n'y a pas un peu trop épiloguer ici. J'ai eu récemment des problèmes avec md5 et les fichiers stockés sous forme de blobs sur MySQL, donc j'expérimenté avec différentes tailles de fichiers et l'approche Python simple, à savoir:

FileHash=hashlib.md5(FileData).hexdigest()

Je ne pouvais détecter aucune différence notable des performances avec une gamme de tailles des fichiers 2Kb 20Mo et donc pas besoin de « morceau » du hachage. Quoi qu'il en soit, si Linux doit aller sur le disque, il sera probablement le faire au moins aussi bien que la capacité du programmeur moyen pour l'empêcher de le faire. Comme il est arrivé, le problème était rien à voir avec md5. Si vous utilisez MySQL, ne pas oublier le md5 () et SHA1 () fonctions déjà.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top