Domanda

Ho usato hashlib (che sostituisce md5 in Python 2.6 / 3.0) e ha funzionato bene se ho aperto un file e mettere il suo contenuto in funzione hashlib.md5() .

Il problema è con file molto grandi che le loro dimensioni possano superare la dimensione della RAM.

Come ottenere l'hash MD5 di un file senza caricare l'intero file in memoria?

È stato utile?

Soluzione

Suddividere il file in blocchi da 128 byte e nutrirli per MD5 consecutivamente utilizzando update().

Questa sfrutta il fatto che MD5 è 128 byte digerire blocchi. Fondamentalmente, quando MD5 digest()s il file, questo è esattamente quello che sta facendo.

Se assicuratevi di liberare la memoria ad ogni iterazione (vale a dire non leggere l'intero file in memoria), tale partecipazione non più di 128 byte di memoria.

Un esempio è quello di leggere i pezzi in questo modo:

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

Altri suggerimenti

Hai bisogno di leggere il file in pezzi di dimensioni adeguate:

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

Nota: Assicurarsi che si apre il file con il 'rb' all'aperto - altrimenti si otterrà il risultato sbagliato

.

Quindi, per fare il tutto in un metodo - usare qualcosa come:

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

L'aggiornamento di cui sopra si è basata sulle osservazioni fornite da Frerich Raabe - e ho provato questo e l'ho trovato per essere corretto sulla mia installazione di Python 2.7.2 finestre

I controllo incrociato i risultati utilizzando lo strumento 'jacksum'.

jacksum -a md5 <filename>

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

se ti interessa di più divinatorio (no 'mentre True') modo di leggere il file di verificare questo codice:

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

Si noti che l'iter () func ha bisogno di una stringa di byte vuota per l'iteratore tornato a fermare a EOF, dal momento che read () restituisce b '' (non solo '').

Ecco la mia versione del metodo di @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()

L'utilizzo di più di commento / risposte in questa discussione, qui è la mia soluzione:

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()
  • Questo è "divinatorio"
  • Questa è una funzione
  • Evita valori impliciti: sempre preferiscono quelli espliciti
  • .
  • Permette (molto importante) prestazioni ottimizzazioni

E, infine,

-. Questo è stato costruito da una comunità, ringrazia tutti per i vostri consigli / idee

un pitone 2/3 soluzione portatile

Per calcolare un checksum (MD5, SHA1, ecc), è necessario aprire il file in modalità binaria, perché si somma bytes valori:

Per essere py27 / PY3 portatile, si dovrebbe utilizzare i pacchetti io, in questo modo:

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

Se i file sono grandi, è preferibile leggere il file da blocchi per evitare di memorizzare l'intero contenuto del file in memoria:

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

Il trucco è quello di utilizzare la funzione iter() con un < em> sentinella (la stringa vuota).

  

L'iteratore creato in questo caso chiamerà o [funzione lambda] senza argomenti per ogni chiamata al suo metodo next(); se il valore restituito è pari a sentinella, StopIteration sarà sollevata, in caso contrario verrà restituito il valore.

Se i file sono davvero grande, potrebbe anche essere necessario per visualizzare le informazioni di avanzamento. Si può fare chiamando una funzione di callback che stampa o registra la quantità di byte calcolati:

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 del codice di Bastien Semene che prendono commento Hawkwing sulla funzione di hashing generica in considerazione ...

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 non può ottenere è md5 senza contenuto completo in lettura. ma u possibile utilizzare aggiornamento funzione per leggere i file di blocco dei contenuti per blocco.
m.update (a); m.update (b) è equivalente a m.update (a + b)

Credo che il seguente codice è più divinatorio:

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

Attuazione della risposta accettata per 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()

Non mi piace il loop. Sulla base di @ 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

Non sono sicuro che non ci sia un po 'troppo irritabili qui intorno. Recentemente ho avuto problemi con MD5 e file memorizzati come macchie su MySQL così ho sperimentato con i vari formati di file e l'approccio di Python semplice, vale a dire:

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

ho potuto rilevare alcuna differenza notevole di prestazioni con una serie di file di dimensioni 2Kb a 20Mb e quindi non c'è bisogno di 'pezzo' l'hashing. In ogni caso, se Linux deve andare sul disco, sarà probabilmente farlo almeno così come la capacità del programmatore medio di tenerlo dal farlo. Come è successo, il problema era niente a che fare con MD5. Se stai usando MySQL, non dimenticate la md5 () e SHA1 () funzioni già lì.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top