[python] 파일의 MD5 체크섬 생성

파이썬에서 파일 목록의 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에서 시작하는 경우의 합계가 실제로 다르기 때문에 빈 문자열로 시작해야합니다. 즉 "", 1CRC는 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이 설치되었다고 가정합니다.


답변