Eu usei o hashlib (que substitui o md5 no Python 2.6 / 3.0) e funcionou bem se eu abrisse um arquivo e colocasse seu conteúdo em hashlib.md5()
função.
O problema é com arquivos muito grandes que seus tamanhos podem exceder o tamanho da RAM.
Como obter o hash MD5 de um arquivo sem carregar o arquivo inteiro na memória?
Respostas:
Divida o arquivo em pedaços de 8192 bytes (ou algum outro múltiplo de 128 bytes) e alimente-os no MD5 consecutivamente usando
update()
.Isso tira proveito do fato de o MD5 ter blocos de resumo de 128 bytes (8192 é 128 × 64). Como você não está lendo o arquivo inteiro na memória, isso não usará muito mais do que 8192 bytes de memória.
No Python 3.8 ou superior, você pode fazer
fonte
hashlib.blake2b
vez demd5
. Ao contrário do MD5, o BLAKE2 é seguro e é ainda mais rápido.Você precisa ler o arquivo em pedaços de tamanho adequado:
NOTA: Certifique-se de abrir seu arquivo com o 'rb' para abrir; caso contrário, você obterá o resultado errado.
Então, para fazer o lote inteiro em um método - use algo como:
A atualização acima foi baseada nos comentários fornecidos por Frerich Raabe - e eu testei isso e achei que estava correto na minha instalação do Windows Python 2.7.2
Eu verifiquei os resultados usando a ferramenta 'jacksum'.
http://www.jonelo.de/java/jacksum/
fonte
rb
para aopen
função.hexdigest
vez dedigest
produzirá um hash hexadecimal que "se parece" com a maioria dos exemplos de hashes.if len(data) < block_size: break
?open
sempre abre um novo identificador de arquivo com a posição definida para o início do arquivo (a menos que você abra um arquivo para anexar).Abaixo incorporei a sugestão dos comentários. Obrigado a todos!
python <3.7
python 3.8 e acima
postagem original
se você se preocupa com a maneira mais pitônica (sem 'enquanto True') de ler o arquivo, verifique este código:
Observe que a função iter () precisa de uma cadeia de bytes vazia para o iterador retornado parar no EOF, pois read () retorna b '' (não apenas '').
fonte
128*md5.block_size
vez de8192
.md5.block_size
.b''
sintaxe era nova para mim. Explicado aqui .Aqui está minha versão do método @Piotr Czapla:
fonte
Usando vários comentários / respostas neste tópico, aqui está minha solução:
E finalmente,
- Isso foi construído por uma comunidade, obrigado a todos por seus conselhos / idéias.
fonte
Uma solução portátil Python 2/3
Para calcular uma soma de verificação (md5, sha1 etc.), você deve abrir o arquivo no modo binário, porque você somará valores de bytes:
Para ser portátil py27 / py3, você deve usar os
io
pacotes, assim:Se seus arquivos forem grandes, convém ler o arquivo em pedaços para evitar armazenar todo o conteúdo do arquivo na memória:
O truque aqui é usar a
iter()
função com uma sentinela (a sequência vazia).Se seus arquivos forem realmente grandes, talvez você também precise exibir informações de progresso. Você pode fazer isso chamando uma função de retorno de chamada que imprime ou registra a quantidade de bytes calculados:
fonte
Um remix do código Bastien Semene que leva em consideração o comentário de Hawkwing sobre a função de hash genérica ...
fonte
você não pode obtê-lo MD5 sem ler o conteúdo completo. mas você pode usar a função de atualização para ler o conteúdo dos arquivos bloco por bloco.
m.update (a); m.update (b) é equivalente a m.update (a + b)
fonte
Eu acho que o código a seguir é mais pitônico:
fonte
Implementação da resposta aceita para o Django:
fonte
Eu não gosto de loops. Baseado em @Nathan Feger:
fonte
hashlib
a API realmente não funciona bem com o restante do Python. Por exemplo, vamos dar umashutil.copyfileobj
olhada que não funciona muito bem. Minha próxima idéia foifold
(akareduce
), que dobra iterables em objetos únicos. Como, por exemplo, um hash.hashlib
não fornece operadores, o que torna isso um pouco complicado. No entanto, estavam dobrando um iterables aqui.fonte
Não tenho certeza de que não haja muita confusão por aqui. Recentemente, tive problemas com md5 e arquivos armazenados como blobs no MySQL, então experimentei vários tamanhos de arquivo e a abordagem direta do Python, a saber:
Não pude detectar nenhuma diferença perceptível de desempenho com uma variedade de tamanhos de arquivo de 2 KB a 20 Mb e, portanto, não há necessidade de "dividir" o hash. De qualquer forma, se o Linux tiver que ir para o disco, provavelmente o fará pelo menos assim como a capacidade do programador médio de impedir que isso aconteça. Por acaso, o problema não estava relacionado ao MD5. Se você estiver usando o MySQL, não esqueça as funções md5 () e sha1 () já existentes.
fonte