ฉันใช้ hashlib (ซึ่งแทนที่ md5 ใน Python 2.6 / 3.0) และใช้งานได้ดีถ้าฉันเปิดไฟล์และวางเนื้อหาไว้ในhashlib.md5()
ฟังก์ชั่น
ปัญหาคือไฟล์ที่มีขนาดใหญ่มากซึ่งขนาดอาจเกินขนาด RAM
วิธีรับ MD5 hash ของไฟล์โดยไม่โหลดทั้งไฟล์ลงในหน่วยความจำ
ฉันใช้ hashlib (ซึ่งแทนที่ md5 ใน Python 2.6 / 3.0) และใช้งานได้ดีถ้าฉันเปิดไฟล์และวางเนื้อหาไว้ในhashlib.md5()
ฟังก์ชั่น
ปัญหาคือไฟล์ที่มีขนาดใหญ่มากซึ่งขนาดอาจเกินขนาด RAM
วิธีรับ MD5 hash ของไฟล์โดยไม่โหลดทั้งไฟล์ลงในหน่วยความจำ
คำตอบ:
แบ่งไฟล์เป็นชิ้น 8192 ไบต์ (หรือบางหลายอื่น ๆ ของ 128 bytes) update()
และอาหารให้พวกเขาอย่างต่อเนื่องโดยใช้
สิ่งนี้ใช้ประโยชน์จากข้อเท็จจริงที่ว่า MD5 มีบล็อกย่อยย่อย 128- ไบต์ (8192 คือ 128 × 64) เนื่องจากคุณไม่ได้อ่านไฟล์ทั้งหมดในหน่วยความจำนี่จะไม่ใช้หน่วยความจำมากกว่า 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
hashlib.blake2b
BLAKE2นั้นmd5
แตกต่างจาก 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'
jacksum -a md5 <filename>
rb
ไปยังopen
ฟังก์ชั่น
hexdigest
แทนที่จะเป็นการdigest
สร้างแฮชเลขฐานสิบหกที่ "ดูเหมือน" จะเป็นตัวอย่างของแฮชส่วนใหญ่
if len(data) < block_size: break
?
open
เสมอโดยกำหนดตำแหน่งไว้ที่จุดเริ่มต้นของไฟล์(เว้นแต่คุณจะเปิดไฟล์เพื่อต่อท้าย)
ด้านล่างฉันได้รวมข้อเสนอแนะจากความคิดเห็น ขอบคุณมาก!
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()
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()
หากคุณสนใจวิธีการอ่าน pythonic เพิ่มเติม (ไม่ 'ในขณะที่ 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 () func ต้องการสตริงไบต์ว่างเพื่อให้ตัววนซ้ำกลับมาหยุดที่ EOF เนื่องจาก read () ส่งคืน b '' (ไม่ใช่แค่ '')
128*md5.block_size
8192
md5.block_size
ขนาด
นี่คือวิธีการของ @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
ในการคำนวณ checksum (md5, sha1 ฯลฯ ) คุณจะต้องเปิดไฟล์ในโหมดไบนารีเพราะคุณจะหาผลรวมของค่าไบต์:
ในการเป็นแบบพกพา py27 / py3 คุณควรใช้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
เคล็ดลับที่นี่คือการใช้iter()
ฟังก์ชั่นกับแมวมอง (สตริงว่าง)
ตัววนซ้ำที่สร้างขึ้นในกรณีนี้จะเรียกo [ฟังก์ชัน lambda] โดยไม่มีอาร์กิวเมนต์สำหรับการเรียกแต่ละครั้งไปยัง
next()
วิธีการ หากค่าที่ส่งคืนเท่ากับ SentinelStopIteration
จะได้รับการเพิ่มขึ้นมิฉะนั้นค่าจะถูกส่งคืน
หากไฟล์ของคุณอยู่จริงๆใหญ่คุณอาจต้องข้อมูลความคืบหน้าการแสดงผล คุณสามารถทำได้โดยการเรียกฟังก์ชั่นโทรกลับซึ่งพิมพ์หรือบันทึกจำนวนไบต์ที่คำนวณได้:
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
รีมิกซ์ของโค้ด Bastien Semene ที่นำความคิดเห็น Hawkwing เกี่ยวกับฟังก์ชันการแปลงแป้นพิมพ์ทั่วไปมาพิจารณา ...
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 (ก); m.update (b) เทียบเท่ากับ m.update (a + b)
ฉันคิดว่ารหัสต่อไปนี้เป็น pythonic เพิ่มเติม:
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()
การใช้คำตอบที่ยอมรับสำหรับ Django:
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()
ฉันไม่ชอบลูป อิงจาก @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()
hashlib
API ของ API นั้นเล่นได้ไม่ดีนักกับ Python ที่เหลือ ตัวอย่างเช่นลองทำshutil.copyfileobj
สิ่งที่ล้มเหลวในการทำงานอย่างใกล้ชิด แนวคิดต่อไปของฉันคือfold
(aka reduce
) ซึ่งพับได้รวมกันเป็นวัตถุเดียว ชอบแฮช hashlib
ไม่ได้ให้ตัวดำเนินการซึ่งทำให้ยุ่งยากเล็กน้อย อย่างไรก็ตามมีการพับ iterables ที่นี่
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
ฉันไม่แน่ใจว่าที่นี่มีเรื่องกวนใจมากเกินไป ฉันเพิ่งมีปัญหาเกี่ยวกับ md5 และไฟล์ที่จัดเก็บเป็น blobs บน MySQL ดังนั้นฉันจึงทดลองกับขนาดไฟล์ที่หลากหลายและวิธี Python ที่ตรงไปตรงมา ได้แก่ :
FileHash=hashlib.md5(FileData).hexdigest()
ฉันสามารถตรวจพบความแตกต่างของประสิทธิภาพที่สังเกตไม่ได้ด้วยช่วงของขนาดไฟล์ 2Kb ถึง 20Mb ดังนั้นจึงไม่จำเป็นต้อง 'บีบ' การแฮช อย่างไรก็ตามถ้า Linux ต้องไปที่ดิสก์มันอาจจะทำอย่างน้อยก็เช่นเดียวกับความสามารถของโปรแกรมเมอร์โดยเฉลี่ยในการป้องกันไม่ให้ทำเช่นนั้น เมื่อมันเกิดขึ้นปัญหาก็ไม่ได้เกี่ยวกับ md5 หากคุณใช้งาน MySQL อย่าลืมฟังก์ชั่น md5 () และ sha1 ()