Najwyraźniej nie dodam niczego zasadniczo nowego, ale dodałem tę odpowiedź, zanim osiągnąłem status komentowania, a regiony kodu wyjaśniają wszystko - w każdym razie, w szczególności, aby odpowiedzieć na pytanie @ Nemo z odpowiedzi Omnifariousa:
Zdarzyło mi się trochę zastanowić nad sumami kontrolnymi (konkretnie przyjechałem tutaj, szukając sugestii dotyczących rozmiarów bloków) i odkryłem, że ta metoda może być szybsza, niż można się było spodziewać. Biorąc najszybszy (ale dość typowy) timeit.timeit
lub /usr/bin/time
wynik z każdej z kilku metod sumowania pliku o wielkości ok. 11 MB:
$ ./sum_methods.py
crc32_mmap(filename) 0.0241742134094
crc32_read(filename) 0.0219960212708
subprocess.check_output(['cksum', filename]) 0.0553209781647
md5sum_mmap(filename) 0.0286180973053
md5sum_read(filename) 0.0311000347137
subprocess.check_output(['md5sum', filename]) 0.0332629680634
$ time md5sum /tmp/test.data.300k
d3fe3d5d4c2460b5daacc30c6efbc77f /tmp/test.data.300k
real 0m0.043s
user 0m0.032s
sys 0m0.010s
$ stat -c '%s' /tmp/test.data.300k
11890400
Wygląda więc na to, że zarówno plik Python, jak i / usr / bin / md5sum zajmuje około 30 ms dla pliku 11 MB. Odpowiednia md5sum
funkcja ( md5sum_read
w powyższej liście) jest bardzo podobna do funkcji Omnifarious:
import hashlib
def md5sum(filename, blocksize=65536):
hash = hashlib.md5()
with open(filename, "rb") as f:
for block in iter(lambda: f.read(blocksize), b""):
hash.update(block)
return hash.hexdigest()
To prawda, że pochodzą z pojedynczych przebiegów ( mmap
te są zawsze o kilka razy szybsze, gdy wykonuje się co najmniej kilkadziesiąt przebiegów), a mój zwykle dostaje dodatkowy f.read(blocksize)
po wyczerpaniu bufora, ale jest dość powtarzalny i pokazuje, że md5sum
w wierszu poleceń jest niekoniecznie szybsze niż implementacja Pythona ...
EDYCJA: Przepraszam za duże opóźnienie, nie patrzyłem na to od jakiegoś czasu, ale aby odpowiedzieć na pytanie @ EdRandall, napiszę implementację Adler32. Nie uruchomiłem jednak testów porównawczych. Jest to w zasadzie to samo, co byłby CRC32: zamiast wywołań init, update i skrót wszystko jest zlib.adler32()
połączeniem:
import zlib
def adler32sum(filename, blocksize=65536):
checksum = zlib.adler32("")
with open(filename, "rb") as f:
for block in iter(lambda: f.read(blocksize), b""):
checksum = zlib.adler32(block, checksum)
return checksum & 0xffffffff
Zauważ, że musi to zaczynać się od pustego łańcucha, ponieważ sumy Adlera rzeczywiście różnią się, gdy zaczynają się od zera w porównaniu do ich sumy ""
, czyli 1
- CRC może 0
zamiast tego zacząć . AND
Jest potrzebne -ing, aby to 32-bitowa liczba całkowita bez znaku, który zapewnia, że zwróci tę samą wartość całej wersjach Pythona.
md5sum
?