J'essaie de calculer la valeur SHA-1 d'un fichier.
J'ai fabriqué ce script:
def hashfile(filepath):
sha1 = hashlib.sha1()
f = open(filepath, 'rb')
try:
sha1.update(f.read())
finally:
f.close()
return sha1.hexdigest()
Pour un fichier spécifique, j'obtiens cette valeur de hachage:8c3e109ff260f7b11087974ef7bcdbdc69a0a3b9
Mais quand je calcule la valeur avec git hash_object, alors j'obtiens cette valeur: d339346ca154f6ed9e92205c3c5c38112e761eb7
Comment se fait-il qu'ils diffèrent? Suis-je en train de faire quelque chose de mal, ou puis-je simplement ignorer la différence?
Pour référence, voici une version plus concise:
def sha1OfFile(filepath):
import hashlib
with open(filepath, 'rb') as f:
return hashlib.sha1(f.read()).hexdigest()
Après réflexion: bien que je ne l'ai jamais vu, je pense qu'il est possible que f.read()
renvoie moins que le fichier complet, ou pour un fichier de plusieurs gigaoctets, pour que f.read () soit à court de Mémoire. Pour l'édification de tout le monde, considérons comment résoudre ce problème: Un premier correctif à cela est:
def sha1OfFile(filepath):
import hashlib
sha = hashlib.sha1()
with open(filepath, 'rb') as f:
for line in f:
sha.update(line)
return sha.hexdigest()
Cependant, il n'y a aucune garantie que '\n'
Apparaît dans le fichier, donc le fait que la boucle for
nous fournira des blocs du fichier qui se terminent par '\n'
Pourrait nous donner le même problème que nous avions à l'origine. Malheureusement, je ne vois aucun moyen Pythonique similaire d'itérer sur des blocs du fichier aussi gros que possible, ce qui, je pense, signifie que nous sommes coincés avec une boucle while True: ... break
Et avec un nombre magique pour la taille du bloc :
def sha1OfFile(filepath):
import hashlib
sha = hashlib.sha1()
with open(filepath, 'rb') as f:
while True:
block = f.read(2**10) # Magic number: one-megabyte blocks.
if not block: break
sha.update(block)
return sha.hexdigest()
Bien sûr, qui peut dire que nous pouvons stocker des chaînes d'un mégaoctet. Nous le pouvons probablement, mais que faire si nous sommes sur un petit ordinateur embarqué?
J'aimerais pouvoir penser à une manière plus propre qui est garantie de ne pas manquer de mémoire sur des fichiers énormes et qui n'a pas de nombres magiques et qui fonctionne aussi bien que la solution Pythonic simple d'origine.