Python에서 파일 해싱


100

나는 파이썬이 EOF를 읽기를 원하므로 sha1이든 md5이든 적절한 해시를 얻을 수 있습니다. 도와주세요. 지금까지 내가 가진 것은 다음과 같습니다.

import hashlib

inputFile = raw_input("Enter the name of the file:")
openedFile = open(inputFile)
readFile = openedFile.read()

md5Hash = hashlib.md5(readFile)
md5Hashed = md5Hash.hexdigest()

sha1Hash = hashlib.sha1(readFile)
sha1Hashed = sha1Hash.hexdigest()

print "File Name: %s" % inputFile
print "MD5: %r" % md5Hashed
print "SHA1: %r" % sha1Hashed

6
그리고 문제는 무엇입니까?
isedev

1
파일을 해시 할 수 있기를 바랍니다. 파일 크기에 관계없이 EOF까지 읽어야합니다.
user3358300 2014

3
그게 정확히하는 일입니다 file.read()-전체 파일을 읽습니다.
isedev 2014

read()방법에 대한 문서 는?
Ignacio Vazquez-Abrams

"해싱이란 무엇입니까?"를 거쳐야합니다.
Sharif Mamun 2014

답변:


140

TL; DR은 버퍼를 사용하여 메모리를 많이 사용하지 않습니다.

우리는 매우 큰 파일 작업의 메모리 의미를 고려할 때 문제의 핵심에 도달 합니다 . 우리는이 나쁜 소년이 2 기가 바이트 파일을 위해 2 기가 바이트의 램을 뒤 흔드는 것을 원하지 않습니다. 그래서 pasztorpisti가 지적했듯이 우리는 그 더 큰 파일을 덩어리로 처리해야합니다!

import sys
import hashlib

# BUF_SIZE is totally arbitrary, change for your app!
BUF_SIZE = 65536  # lets read stuff in 64kb chunks!

md5 = hashlib.md5()
sha1 = hashlib.sha1()

with open(sys.argv[1], 'rb') as f:
    while True:
        data = f.read(BUF_SIZE)
        if not data:
            break
        md5.update(data)
        sha1.update(data)

print("MD5: {0}".format(md5.hexdigest()))
print("SHA1: {0}".format(sha1.hexdigest()))

우리가 한 것은 hashlib의 편리한 멋쟁이 업데이트 방법 과 함께 진행하면서이 나쁜 소년의 해시를 64kb 청크로 업데이트하는 것 입니다. 이런 식으로 우리는 한 번에 해시하는 데 걸리는 2GB보다 훨씬 적은 메모리를 사용합니다!

다음과 같이 테스트 할 수 있습니다.

$ mkfile 2g bigfile
$ python hashes.py bigfile
MD5: a981130cf2b7e09f4686dc273cf7187e
SHA1: 91d50642dd930e9542c39d36f0516d45f4e1af0d
$ md5 bigfile
MD5 (bigfile) = a981130cf2b7e09f4686dc273cf7187e
$ shasum bigfile
91d50642dd930e9542c39d36f0516d45f4e1af0d  bigfile

도움이 되었기를 바랍니다.

또한이 모든 내용은 오른쪽의 링크 된 질문에 설명되어 있습니다. Python에서 큰 파일의 MD5 해시 가져 오기


추가!

일반적으로 파이썬을 작성할 때 pep-8 을 따르는 습관을들이는 것이 도움이됩니다 . 예를 들어, 파이썬에서 변수는 일반적으로 camelCased가 아닌 밑줄로 구분됩니다. 그러나 그것은 단지 스타일 일 뿐이고 나쁜 스타일을 읽어야하는 사람들을 제외하고는 아무도 그런 것들을 신경 쓰지 않습니다.


. 안녕하세요 @ranman, 나는 {0} '형식 (sha1.hexdigest ()) 부분을 가져올 수 없습니다 왜 우리가 (sha1.hexdigest을 사용하는 대신 그것을 사용합니까).?
타락한 천사

@Belial 무엇이 작동하지 않았습니까? 나는 주로 그냥이 ... 두 해시를 구별하기 위해 사용되었다
랜달 사냥

@ranman 모든 것이 작동하고 있습니다. 나는 이것을 사용하지 않았고 문학에서 본 적이 없습니다. "{0}". format () ... 알 수 없습니다. :)
Belial 2015 년

1
어떻게 선택해야 BUF_SIZE합니까?
Martin Thoma

1
이것은 shasum바이너리 와 동일한 결과를 생성하지 않습니다 . 아래 나열된 다른 답변 (memoryview를 사용하는 답변)은 다른 해싱 도구와 호환됩니다.
tedivm

61

파일의 해시 값을 정확하고 효율적으로 계산하려면 (Python 3에서) :

  • 이진 모드 (즉, 파일 모드에 추가)에서 파일을 열어 'b'문자 인코딩 및 줄 끝 변환 문제를 방지합니다.
  • 메모리 낭비이기 때문에 전체 파일을 메모리로 읽지 마십시오. 대신 블록별로 순차적으로 읽고 각 블록의 해시를 업데이트하십시오.
  • 이중 버퍼링을 제거합니다. 즉, 이미 최적의 블록 크기를 사용하고 있으므로 버퍼링 된 IO를 사용하지 마십시오.
  • readinto()버퍼 변동을 방지하는 데 사용 합니다.

예:

import hashlib

def sha256sum(filename):
    h  = hashlib.sha256()
    b  = bytearray(128*1024)
    mv = memoryview(b)
    with open(filename, 'rb', buffering=0) as f:
        for n in iter(lambda : f.readinto(mv), 0):
            h.update(mv[:n])
    return h.hexdigest()

2
최적의 블록 크기가 무엇인지 어떻게 알 수 있습니까?
Mitar

1
@Mitar에서 하한은 물리적 블록 (일반적으로 512 바이트 또는 최신 디스크의 경우 4KiB)과 시스템 페이지 크기 (많은 시스템에서 4KiB, 기타 일반적인 선택 : 8KiB 및 64KiB)의 최대 값입니다. 그런 다음 기본적으로 벤치마킹을 수행하거나 게시 된 벤치 마크 결과 및 관련 작업을 살펴 봅니다 (예 : 현재 rsync / GNU cp / ... 사용 여부 확인).
maxschlepzig

겠습니까 resource.getpagesize우리가 다소 동적으로 최적화 원했고 경우, 여기에 어떤 유용 할? 그리고 어떻 mmap습니까?
jpmc26

@ jpmc26, getpagesize ()는 여기서 그다지 유용하지 않습니다. 일반적인 값은 4KiB 또는 8KiB이며, 그 범위에있는 것입니다. 즉, 128KiB-128KiB보다 훨씬 작은 것이 일반적으로 좋은 선택입니다. mmap은 전체 파일을 앞뒤로 순차적으로 읽으므로 사용 사례에서별로 도움이되지 않습니다. mmap은 페이지가 두 번 이상 액세스되는 경우 및 / 또는 mmap이 읽기 버퍼 관리를 단순화하는 경우와 같이 액세스 패턴이 더 랜덤 액세스 일 때 이점이 있습니다.
maxschlepzig

3
나는 약 116GB의 파일과 sha1sum 알고리즘을 사용하여 (1) @Randall Hunt 및 (2) 귀하의 솔루션 (이 순서대로 파일 캐시로 인해 중요 함)을 벤치마킹했습니다. 솔루션 1은 20 * 4096 (PAGE_SIZE)의 버퍼를 사용하고 버퍼링 매개 변수를 0으로 설정하기 위해 수정되었습니다. 솔루션 2 전용 알고리즘이 수정되었습니다 (sha256-> sha1). 결과 : (1) 3m37.137s (2) 3m30.003s. 바이너리 모드의 네이티브 sha1sum : 3m31.395s
bioinfornatics

18

나는 간단히 제안 할 것이다 :

def get_digest(file_path):
    h = hashlib.sha256()

    with open(file_path, 'rb') as file:
        while True:
            # Reading is buffered, so we can read smaller chunks.
            chunk = file.read(h.block_size)
            if not chunk:
                break
            h.update(chunk)

    return h.hexdigest()

여기에있는 다른 모든 답변은 너무 복잡해 보입니다. 파이썬은 읽을 때 이미 버퍼링 중입니다 (이상적인 방식으로 또는 기본 저장소에 대한 더 많은 정보가있는 경우 해당 버퍼링을 구성합니다). 따라서 해시 함수가 이상적인 것을 찾는 청크 단위로 읽는 것이 좋습니다. 해시 함수를 계산합니다. 따라서 버퍼링을 비활성화하고 직접 에뮬레이션하는 대신 Python 버퍼링을 사용하고 제어해야하는 항목, 즉 데이터 소비자가 이상적인 해시 블록 크기를 찾는 항목을 제어합니다.


완벽한 대답이지만 관련 문서 인 Python3-open ()Python2-open ()으로 명령문을 뒷받침한다면 좋을 것 입니다. 둘 사이의 차이점을 염두에 두더라도 Python3의 접근 방식은 더 정교합니다. 그럼에도 불구하고 저는 소비자 중심의 관점에 정말 감사했습니다!
Murmel

hash.block_size'해시 알고리즘의 내부 블록 크기'로 문서화됩니다. Hashlib 이상적 이라고 생각 하지 않습니다 . 패키지 문서의 어떤 것도 크기 입력 을 update()선호 한다고 제안하지 않습니다 hash.block_size. 그렇게 부르면 CPU를 덜 사용하지 않습니다. 귀하의 file.read()새 덩어리가 객체를 바이트로 파일에서 많은 불필요한 객체의 작품과 불필요한 복사본 콜 리드 버퍼.
maxschlepzig

해시는 block_size청크로 상태를 업데이트 합니다. 해당 청크로 제공하지 않는 경우 버퍼링하고 충분한 데이터가 나타날 때까지 기다리거나 주어진 데이터를 내부적으로 청크로 분할해야합니다. 따라서 외부에서 처리 한 다음 내부에서 일어나는 일을 단순화 할 수 있습니다. 나는이 이상을 찾습니다. 예 : stackoverflow.com/a/51335622/252025
Mitar

block_size유용한 읽기 크기보다 훨씬 작다. 또한 유용한 블록 및 읽기 크기는 2의 제곱입니다. 따라서 읽기 크기는 마지막 읽기를 제외한 모든 읽기의 블록 크기로 나눌 수 있습니다. 예를 들어 sha256 블록 크기는 64 바이트입니다. 즉 update(),의 배수까지 버퍼링하지 않고도 입력을 직접 처리 할 수 ​​있습니다 block_size. 따라서 마지막 읽기가 블록 크기로 나눌 수없는 경우에만 최대 63 바이트까지 버퍼링해야합니다. 따라서 귀하의 마지막 의견은 정확하지 않으며 귀하의 답변에서 주장하는 주장을 뒷받침하지 않습니다.
maxschlepzig

요점은 읽을 때 이미 파이썬에서 버퍼링을 수행했기 때문에 버퍼링을 최적화 할 필요가 없다는 것입니다. 따라서 기존 버퍼에 대해 해싱 할 때 수행 할 루프의 양을 결정하기 만하면됩니다.
Mitar 2011

5

다른 알고리즘으로 큰 파일을 해시 할 수있는 모듈을 프로그래밍했습니다.

pip3 install py_essentials

다음과 같이 모듈을 사용하십시오.

from py_essentials import hashing as hs
hash = hs.fileChecksum("path/to/the/file.txt", "sha256")

5

다음은 mmap객체를 메모리에 매핑 하는 데 사용하는 Python 3, POSIX 솔루션 (Windows가 아닙니다!)입니다 .

import hashlib
import mmap

def sha256sum(filename):
    h  = hashlib.sha256()
    with open(filename, 'rb') as f:
        with mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) as mm:
            h.update(mm)
    return h.hexdigest()

순진한 질문 ... mmap이 시나리오에서 사용하면 어떤 이점 이 있습니까?
Jonathan B.

1
@JonathanB. 대부분의 메서드는 불필요하게 bytes메모리에 개체를 만들고 read너무 많이 또는 너무 적게 호출 합니다. 이렇게하면 파일이 가상 메모리에 직접 매핑되고 거기에서 해시됩니다. 운영 체제는 파일 내용을 버퍼 캐시에서 읽기 프로세스로 직접 매핑 할 수 있습니다. 이것은이 이상 중요한 요소가 빠를 수 있음을 의미 이 한
안티 Haapala

@JonathanB. 나는 테스트를하고의 차이는 상당한 것이없는 경우, 우리는 순진 방법보다 ~ 15 %에 대해 얘기하고.
Antti Haapala

-2
import hashlib
user = input("Enter ")
h = hashlib.md5(user.encode())
h2 = h.hexdigest()
with open("encrypted.txt","w") as e:
    print(h2,file=e)


with open("encrypted.txt","r") as e:
    p = e.readline().strip()
    print(p)

2
당신은 기본적으로 echo $USER_INPUT | md5sum > encrypted.txt && cat encrypted.txt파일의 해싱을 다루지 않고, 특히 큰 파일을 다루지 않습니다.
Murmel

1
해시 = 암호화!
bugmenot123
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.