我已经使用hashlib(这在Python 2.6 / 3.0替换MD5),如果我打开一个文件,并把它的内容在它工作得很好hashlib.md5()函数。
问题是与它们的大小可能会超过RAM容量非常大的文件。
如何获得文件的MD5哈希值,而无需加载整个文件到内存?
Answer 1:
打破文件到128字节的块,并连续地使用它们馈送到MD5 update()
这需要的事实,MD5具有128字节的摘要块的优势。 基本上,当MD5 digest() s文件,这正是它在做什么。
如果你确保你释放在每次迭代的内存(即无法读取整个文件到内存),这应采取不超过128字节的内存。
一个例子是读取数据块,像这样:
f = open(fileName)
while not endOfFile:
f.read(128)
Answer 2:
你需要读取合适大小的块中的文件:
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拉贝提出的意见 - 我试用了一下,发现它是正确的我的Python 2.7.2 windows安装
我反复核对使用“jacksum”工具的结果。
jacksum -a md5
http://www.jonelo.de/java/jacksum/
Answer 3:
如果你关心更Python(无“而真正的”)的读取文件检查此编码方式:
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“”(不只是“”)。
Answer 4:
这里是我的@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()
Answer 5:
使用这个线程多评论/答案,这里是我的解决方案:
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的”
这是一个功能
它避免了隐含值:总是喜欢那些明确。
它允许(非常重要)表演的优化
最后,
-这已经由一个社区而建,感谢大家的意见/建议。
Answer 6:
一个Python 2/3的便携式解决方案
计算校验(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()函数使用Sentinel(空字符串)。
在这种情况下创建的迭代器将调用的问题o [lambda函数]不带参数为每个呼叫到其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
Answer 7:
巴斯蒂安的代码义素混音称取约通用散列函数考虑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
Answer 8:
不能得到的,它是不阅读完整内容MD5。 但你可以使用更新功能块来读取文件中的内容块。
m.update(一); m.update(b)是相当于m.update(A + B)
Answer 9:
我认为下面的代码是更Python:
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()
Answer 10:
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()
Answer 11:
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
Answer 12:
我不知道有是不是有点过分大惊小怪这里。 我最近有存储在MySQL斑点MD5和文件的问题,所以我尝试了各种文件大小和简单的Python的办法,即:
FileHash=hashlib.md5(FileData).hexdigest()
我可以检测与一系列文件没有明显的性能差异大小2K位为20MB,因此没有必要“块”的散列。 无论如何,如果Linux有去到磁盘上,它可能会做它至少和一般的程序员的保持它这样做的能力。 因为它发生,问题是无关MD5。 如果你使用MySQL,不要忘了MD5()和SHA1()函数已经存在。
文章来源: Get MD5 hash of big files in Python