programing

Python에서 대용량 파일의 MD5 해시 가져오기

itmemos 2023. 7. 1. 08:04
반응형

Python에서 대용량 파일의 MD5 해시 가져오기

저는 hashlib(Python 2.6/3.0에서 md5를 대체함)을 사용해 보았는데, 파일을 열고 그 내용을 함수에 넣으면 잘 작동했습니다.

문제는 파일 크기가 RAM 크기를 초과할 수 있다는 점입니다.

전체 파일을 메모리에 로드하지 않고 파일의 MD5 해시를 가져올 수 있는 방법은 무엇입니까?

적절한 크기의 청크로 파일을 읽어야 합니다.

def md5_for_file(f, block_size=2**20):
    md5 = hashlib.md5()
    while True:
        data = f.read(block_size)
        if not data:
            break
        md5.update(data)
    return md5.digest()

참고: 'rb'가 있는 파일을 열려 있는지 확인하십시오. 그렇지 않으면 잘못된 결과를 얻을 수 있습니다.

따라서 한 가지 방법으로 전체 로트를 수행하려면 다음과 같은 방법을 사용합니다.

def generate_file_md5(rootdir, filename, blocksize=2**20):
    m = hashlib.md5()
    with open( os.path.join(rootdir, filename) , "rb" ) as f:
        while True:
            buf = f.read(blocksize)
            if not buf:
                break
            m.update( buf )
    return m.hexdigest()

위의 업데이트는 Frerich Raabe가 제공한 코멘트를 기반으로 했습니다. 그리고 저는 이것을 테스트했고 그것이 제 Python 2.7.2 Windows 설치에서 정확하다는 것을 발견했습니다.

는 잭섬 툴을 사용하여 결과를 교차 확인했습니다.

jacksum -a md5 <filename>

청크( 128바이트의로 파일바 8192또이청로 (는 128이트다배른) 수에다 MD5니합을 합니다.update().

이는 MD5에 128바이트 다이제스트 블록(8192는 128x64)이 있다는 점을 활용합니다.전체 파일을 메모리로 읽지 않으므로 8192바이트 이상의 메모리를 사용하지 않습니다.

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

파이썬 < 3.7

import hashlib

def checksum(filename, hash_factory=hashlib.md5, chunk_num_blocks=128):
    h = hash_factory()
    with open(filename,'rb') as f: 
        for chunk in iter(lambda: f.read(chunk_num_blocks*h.block_size), b''): 
            h.update(chunk)
    return h.digest()

Python 3.8 이상

import hashlib

def checksum(filename, hash_factory=hashlib.md5, chunk_num_blocks=128):
    h = hash_factory()
    with open(filename,'rb') as f: 
        while chunk := f.read(chunk_num_blocks*h.block_size): 
            h.update(chunk)
    return h.digest()

원본 게시물

만약 당신이 더 피톤식을 원한다면 (아니오.while True파일을 읽는 방법은 다음 코드를 확인하십시오.

import hashlib

def checksum_md5(filename):
    md5 = hashlib.md5()
    with open(filename,'rb') as f: 
        for chunk in iter(lambda: f.read(8192), b''): 
            md5.update(chunk)
    return md5.digest()

로 고는 다음과 .iter()는 반환된 에서 정지하려면 빈 합니다.read()아온다를 합니다.b''(뿐만 아니라)'').

Piotr Czapla의 방법에 대한 제 버전은 다음과 같습니다.

def md5sum(filename):
    md5 = hashlib.md5()
    with open(filename, 'rb') as f:
        for chunk in iter(lambda: f.read(128 * md5.block_size), b''):
            md5.update(chunk)
    return md5.hexdigest()

이 질문에 대한 여러 의견/답변을 사용하여 다음과 같은 해결책을 제시합니다.

import hashlib
def md5_for_file(path, block_size=256*128, hr=False):
    '''
    Block size directly depends on the block size of your filesystem
    to avoid performances issues
    Here I have blocks of 4096 octets (Default NTFS)
    '''
    md5 = hashlib.md5()
    with open(path,'rb') as f:
        for chunk in iter(lambda: f.read(block_size), b''):
             md5.update(chunk)
    if hr:
        return md5.hexdigest()
    return md5.digest()
  • 이것은 파이썬입니다.
  • 이것은 함수입니다.
  • 암묵적인 값을 피합니다. 항상 명시적인 값을 선호합니다.
  • 성능 최적화(매우 중요)가 가능합니다.

Python 2/3 휴대용 솔루션

체크섬(md5, sha1 등)을 계산하려면 바이트 값을 합하므로 이진 모드에서 파일을 열어야 합니다.

2이식할 수 Python 2.7을 해야 .io다음과 같은 패키지:

import hashlib
import io


def md5sum(src):
    md5 = hashlib.md5()
    with io.open(src, mode="rb") as fd:
        content = fd.read()
        md5.update(content)
    return md5

파일 크기가 큰 경우 전체 파일 내용을 메모리에 저장하지 않도록 파일을 청크로 읽는 것이 좋습니다.

def md5sum(src, length=io.DEFAULT_BUFFER_SIZE):
    md5 = hashlib.md5()
    with io.open(src, mode="rb") as fd:
        for chunk in iter(lambda: fd.read(length), b''):
            md5.update(chunk)
    return md5

여기서 요령은 함수를 센티널(빈 문자열)과 함께 사용하는 것입니다.

이 경우 생성된 반복기는 각 호출에 대한 인수 없이 [람다 함수]를 호출합니다.next()방법; 반환되는 값이 보초와 같다면,StopIteration값이 상승합니다. 그렇지 않으면 값이 반환됩니다.

파일이 정말 큰 경우 진행률 정보를 표시해야 할 수도 있습니다.이렇게 하려면 계산된 바이트 양을 인쇄하거나 기록하는 콜백 함수를 호출합니다.

def md5sum(src, callback, length=io.DEFAULT_BUFFER_SIZE):
    calculated = 0
    md5 = hashlib.md5()
    with io.open(src, mode="rb") as fd:
        for chunk in iter(lambda: fd.read(length), b''):
            md5.update(chunk)
            calculated += len(chunk)
            callback(calculated)
    return md5

일반 해싱 기능에 대한 호크윙의 코멘트를 고려바스티앙 세메네의 코드 리믹스...

def hash_for_file(path, algorithm=hashlib.algorithms[0], block_size=256*128, human_readable=True):
    """
    Block size directly depends on the block size of your filesystem
    to avoid performances issues
    Here I have blocks of 4096 octets (Default NTFS)

    Linux Ext4 block size
    sudo tune2fs -l /dev/sda5 | grep -i 'block size'
    > Block size:               4096

    Input:
        path: a path
        algorithm: an algorithm in hashlib.algorithms
                   ATM: ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')
        block_size: a multiple of 128 corresponding to the block size of your filesystem
        human_readable: switch between digest() or hexdigest() output, default hexdigest()
    Output:
        hash
    """
    if algorithm not in hashlib.algorithms:
        raise NameError('The algorithm "{algorithm}" you specified is '
                        'not a member of "hashlib.algorithms"'.format(algorithm=algorithm))

    hash_algo = hashlib.new(algorithm)  # According to hashlib documentation using new()
                                        # will be slower then calling using named
                                        # constructors, ex.: hashlib.md5()
    with open(path, 'rb') as f:
        for chunk in iter(lambda: f.read(block_size), b''):
             hash_algo.update(chunk)
    if human_readable:
        file_hash = hash_algo.hexdigest()
    else:
        file_hash = hash_algo.digest()
    return file_hash

전체 내용을 읽지 않고는 md5를 얻을 수 없습니다.그러나 업데이트 기능을 사용하여 파일의 내용을 블록 단위로 읽을 수 있습니다.

m.update(a); m.update(b)는 m.update(a+b)동일합니다.

저는 다음 코드가 파이썬적이라고 생각합니다.

from hashlib import md5

def get_md5(fname):
    m = md5()
    with open(fname, 'rb') as fp:
        for chunk in fp:
            m.update(chunk)
    return m.hexdigest()

저는 루프를 좋아하지 않습니다.Nathan Feger의 답변을 기반으로 합니다.

md5 = hashlib.md5()
with open(filename, 'rb') as f:
    functools.reduce(lambda _, c: md5.update(c), iter(lambda: f.read(md5.block_size * 128), b''), None)
md5.hexdigest()

장고에 대한 유발 아담의 답변 이행:

import hashlib
from django.db import models

class MyModel(models.Model):
    file = models.FileField()  # Any field based on django.core.files.File

    def get_hash(self):
        hash = hashlib.md5()
        for chunk in self.file.chunks(chunk_size=8192):
            hash.update(chunk)
        return hash.hexdigest()

저는 이 근처에 너무 많은 소란이 있는지 잘 모르겠습니다.저는 최근에 MySQL에 blobs로 저장된 md5와 파일에 문제가 있어서 다양한 파일 크기와 간단한 Python 접근법인 viz:

FileHash = hashlib.md5(FileData).hexdigest()

파일 크기가 2KB에서 20MB 사이인 경우 뚜렷한 성능 차이를 감지할 수 없었기 때문에 해시를 '청크'할 필요가 없습니다.어쨌든, 리눅스가 디스크로 가야 한다면, 적어도 평균적인 프로그래머의 능력만큼 그렇게 하지 않을 것입니다.공교롭게도, 그 문제는 md5와는 무관합니다.MySQL을 사용하는 경우 이미 md5() 및 sha1() 함수를 사용하는 것을 잊지 마십시오.

import hashlib,re
opened = open('/home/parrot/pass.txt','r')
opened = open.readlines()
for i in opened:
    strip1 = i.strip('\n')
    hash_object = hashlib.md5(strip1.encode())
    hash2 = hash_object.hexdigest()
    print hash2

언급URL : https://stackoverflow.com/questions/1131220/get-the-md5-hash-of-big-files-in-python

반응형