Ich versuche, den SHA-1-Wert einer Datei zu berechnen.
Ich habe dieses Skript erstellt:
def hashfile(filepath):
sha1 = hashlib.sha1()
f = open(filepath, 'rb')
try:
sha1.update(f.read())
finally:
f.close()
return sha1.hexdigest()
Für eine bestimmte Datei bekomme ich diesen Hashwert:
8c3e109ff260f7b11087974ef7bcdbdc69a0a3b9
Aber wenn ich den Wert mit git hash_object berechne, dann bekomme ich diesen Wert: d339346ca154f6ed9e92205c3c5c38112e761eb7
Wie kommt es, dass sie sich unterscheiden? Mache ich etwas falsch oder kann ich den Unterschied einfach ignorieren?
git berechnet Hashes wie folgt:
sha1("blob " + filesize + "\0" + data)
Bezug
Als Referenz, hier ist eine kürzere Version:
def sha1OfFile(filepath):
import hashlib
with open(filepath, 'rb') as f:
return hashlib.sha1(f.read()).hexdigest()
Auf den zweiten Blick: Obwohl ich es noch nie gesehen habe, denke ich, dass es Potenzial dafür gibt f.read()
um weniger als die vollständige Datei zurückzugeben, oder bei einer Datei mit vielen Gigabyte, damit f.read() nicht mehr genügend Arbeitsspeicher zur Verfügung steht. Lassen Sie uns zur Erbauung aller darüber nachdenken, wie das behoben werden kann: Eine erste Lösung dafür ist:
def sha1OfFile(filepath):
import hashlib
sha = hashlib.sha1()
with open(filepath, 'rb') as f:
for line in f:
sha.update(line)
return sha.hexdigest()
Allerdings gibt es dafür keine Garantie '\n'
überhaupt in der Datei auftaucht, also die Tatsache, dass die for
Schleife gibt uns Blöcke der Datei, die auf enden '\n'
könnte uns das gleiche Problem geben, das wir ursprünglich hatten. Leider sehe ich keinen ähnlich pythonischen Weg, um möglichst große Blöcke der Datei zu durchlaufen, was meiner Meinung nach bedeutet, dass wir bei a festsitzen while True: ... break
Schleife und mit einer magischen Zahl für die Blockgröße:
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()
Wer sagt natürlich, dass wir Ein-Megabyte-Strings speichern können? Wahrscheinlich können wir das, aber was ist, wenn wir uns auf einem winzigen eingebetteten Computer befinden?
Ich wünschte, ich könnte mir einen saubereren Weg vorstellen, der bei riesigen Dateien garantiert nicht zu wenig Speicher hat und der keine magischen Zahlen hat und der so gut funktioniert wie die ursprüngliche einfache Pythonic-Lösung.
Sie können den Unterschied nicht wirklich ignorieren, wenn Sie vorhaben, die Hashes zusammen zu verwenden.
– Matthew Scharley
8. Dezember 2009 um 21:16 Uhr
Ich habe vergessen zu erwähnen, dass ich nur Git als Referenz verwendet habe und sie nicht zusammen verwenden werde.
– Ikke
8. Dezember 2009 um 21:24 Uhr
Wenn die Datei ziemlich groß sein könnte, können Sie sie blockweise verarbeiten, sodass Sie nicht das Ganze auf einmal im RAM benötigen: stackoverflow.com/questions/7829499/…
– rakslice
1. August 2013 um 18:24 Uhr
Mögliches Duplikat von Wie berechnet Git Datei-Hashes? Minimalbeispiele 😉
– Ciro Santilli Путлер Капут 六四事
17. Mai 2016 um 10:14 Uhr