파이썬에서 파일 목록의 MD5 체크섬을 생성하고 확인하는 간단한 방법이 있습니까? (작업중 인 작은 프로그램이 있으며 파일의 체크섬을 확인하고 싶습니다).
답변
hashlib.md5 ()를 사용할 수 있습니다
때로는 전체 파일을 메모리에 맞추지 못할 수도 있습니다. 이 경우 순차적으로 4096 바이트의 청크를 읽고 md5
메소드에 피드해야합니다 .
import hashlib
def md5(fname):
hash_md5 = hashlib.md5()
with open(fname, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
참고 : 압축 된 바이트 use 만 필요하면 다이제스트에 대한 16 진수 문자열 표현을 hash_md5.hexdigest()
반환 하므로 다시 변환 할 필요가 없습니다.return hash_md5.digest()
답변
꽤 비효율적 인 방법이 있습니다.
하나의 파일:
import hashlib
def file_as_bytes(file):
with file:
return file.read()
print hashlib.md5(file_as_bytes(open(full_path, 'rb'))).hexdigest()
파일 목록 :
[(fname, hashlib.md5(file_as_bytes(open(fname, 'rb'))).digest()) for fname in fnamelst]
그러나 MD5는 고장난 것으로 알려져 있으며 취약성 분석이 실제로 까다로울 수 있기 때문에 어떤 목적으로도 사용해서는 안된다는 점을 기억 하십시오. 향후 발생할 수있는 사용을 분석하는 것은 보안 문제로 인해 불가능할 수 있습니다. IMHO, 라이브러리에서 평평하게 제거해야 라이브러리를 사용하는 모든 사람이 강제로 업데이트됩니다. 따라서 대신 수행해야 할 작업은 다음과 같습니다.
[(fname, hashlib.sha256(file_as_bytes(open(fname, 'rb'))).digest()) for fname in fnamelst]
128 비트의 다이제스트 만 원한다면 할 수 있습니다 .digest()[:16]
.
그러면 파일 이름과 해시가 들어있는 튜플 목록이 나타납니다.
다시 한 번 MD5 사용에 의문을 제기합니다. 최소한 SHA1을 사용해야 하고 SHA1 에서 발견 된 최근 결함이 있을 수 있습니다. 어떤 사람들은 MD5를 ‘암호화’목적으로 사용하지 않는 한 괜찮다고 생각합니다. 그러나 물건은 처음에 예상했던 것보다 범위가 넓어지는 경향이 있으며 일시적인 취약점 분석에 완전히 결함이있을 수 있습니다. 게이트에서 올바른 알고리즘을 사용하는 습관을들이는 것이 가장 좋습니다. 그냥 다른 문자를 입력하는 것입니다. 그렇게 어렵지 않습니다.
더 복잡하지만 메모리 효율적인 방법은 다음과 같습니다 .
import hashlib
def hash_bytestr_iter(bytesiter, hasher, ashexstr=False):
for block in bytesiter:
hasher.update(block)
return hasher.hexdigest() if ashexstr else hasher.digest()
def file_as_blockiter(afile, blocksize=65536):
with afile:
block = afile.read(blocksize)
while len(block) > 0:
yield block
block = afile.read(blocksize)
[(fname, hash_bytestr_iter(file_as_blockiter(open(fname, 'rb')), hashlib.md5()))
for fname in fnamelst]
그리고 다시, MD5가 손상되어 더 이상 사용해서는 안됩니다.
[(fname, hash_bytestr_iter(file_as_blockiter(open(fname, 'rb')), hashlib.sha256()))
for fname in fnamelst]
다시 말하지만 128 비트의 다이제스트 만 원한다면 [:16]
호출 후에 넣을 수 있습니다 hash_bytestr_iter(...)
.
답변
나는 근본적으로 새로운 것을 추가하지는 않지만 상태를 주석 처리하기 전에이 답변을 추가했으며 코드 영역은 상황을보다 명확하게 만듭니다. 어쨌든 Omnifarious의 답변에서 @Nemo의 질문에 대답합니다.
나는 체크섬에 대해 조금 생각하고 있었고 (특히 블록 크기에 대한 제안을 찾으러 왔음)이 방법이 예상보다 빠르다는 것을 알았습니다. 파일을 대략적으로 검사하는 여러 가지 방법 을 사용하여 가장 빠르 timeit.timeit
거나 (일반적인) /usr/bin/time
결과를 얻습니다. 11MB :
$ ./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
따라서 파이썬과 / usr / bin / md5sum 모두 11MB 파일에 약 30ms가 걸리는 것처럼 보입니다. 위의 목록에서 관련 md5sum
기능 md5sum_read
은 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()
물론, 이것은 단일 런 mmap
에서 (적어도 수십 번 런을 할 때 항상 더 빠릅니다), f.read(blocksize)
버퍼는 고갈 된 후에 일반적으로 여분 을 얻지 만 합리적으로 반복 가능하며 md5sum
명령 줄에 반드시 파이썬 구현보다 빠를 필요는 없습니다 …
편집 : 오랜 지연에 대해 죄송합니다. 한동안 이것을 보지 못했지만 @EdRandall의 질문에 대답하기 위해 Adler32 구현을 작성하겠습니다. 그러나 벤치 마크를 실행하지 않았습니다. 기본적으로 CRC32와 동일합니다. init, update 및 digest 호출 대신 모든 것이 zlib.adler32()
호출입니다.
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
Adler 합계는 0에서 시작하는 경우의 합계가 실제로 다르기 때문에 빈 문자열로 시작해야합니다. 즉 ""
, 1
CRC는 0
대신 시작할 수 있습니다 . AND
-ing은이 파이썬 버전에서 동일한 값을 반환 보장하는 32 비트 부호없는 정수 만들 필요합니다.
답변
Python 3.8 이상에서는 할 수 있습니다
import hashlib
with open("your_filename.txt", "rb") as f:
file_hash = hashlib.md5()
while chunk := f.read(8192):
file_hash.update(chunk)
print(file_hash.digest())
print(file_hash.hexdigest()) # to get a printable str instead of bytes
사용을 고려 hashlib.blake2b
하는 대신 md5
(만 교체 md5
와 함께 blake2b
위의 미리보기에서). 암호화 적으로 안전하고 MD5보다 빠릅니다 .
답변
hashlib.md5(pathlib.Path('path/to/file').read_bytes()).hexdigest()
답변
패키지 호출에 의존하고 md5sum 바이너리는 하위 프로세스 또는 md5 패키지보다 조금 더 편리하다고 생각합니다.
import invoke
def get_file_hash(path):
return invoke.Context().run("md5sum {}".format(path), hide=True).stdout.split(" ")[0]
물론 이것은 호출하고 md5sum이 설치되었다고 가정합니다.