快速文件hash
Posted 猛禽
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了快速文件hash相关的知识,希望对你有一定的参考价值。
最近打算把家里服务器上的文件理一下,想把重复的文件找出来,虽然我已经用了ZFS的dedup,实际占用空间并不会重复,但是还是觉得有必要理一下……
写个程序扫描一遍并不复杂,但是要判断文件是不是重复就比较麻烦,可靠的方法当然是做全文件HASH,但是对于T级的硬盘来说,这样效率太低了,所以写了一段小代码来做一个快速的HASH。
def get_filemd5(fullpath, filename):
file_size = get_filesize(fullpath, filename)
block_count = int((QUICK_HASH_SIZE + BUFSIZE / 2) / BUFSIZE
if QUICK_HASH_SIZE else file_size / BUFSIZE)
block_size = file_size * 1.0 / block_count if QUICK_HASH_SIZE \\
else BUFSIZE
m = hashlib.md5()
with open(os.path.join(fullpath, filename), "rb") as f:
for i in xrange(block_count):
pos = int(i * block_size / MINSIZE) * MINSIZE
f.seek(pos, 0)
buf = f.read(BUFSIZE)
m.update(buf)
remaining = file_size - f.tell()
if remaining > 0:
if QUICK_HASH_SIZE and remaining > BUFSIZE:
f.seek(file_size - BUFSIZE, 0)
remaining = BUFSIZE
buf = f.read(remaining)
m.update(buf)
return m.hexdigest()
HASH算法是直接用MD5,简单方便。其中定义了三个常量:QUICK_HASH_SIZE、BUFSIZE和MINSIZE。
其中MINSIZE定义了对齐的大小,BUFSIZE定义了HASH分块的大小,QUICK_HASH_SIZE则是定义了需要做快速HASH的文件大小阈值。
方法很简单:文件小于QUICK_HASH_SIZE,则做全文件HASH,大于QUICK_HASH_SIZE则按BUFSIZE大小间隔取样,总取样数据大小为QUICK_HASH_SIZE。
每个BUFSIZE块在文件中的分布为均匀的,但是每块又以MINSIZE对齐,另外,因为通常文件最经常被修改的部分是最后的部分,所以最后一块一定是与文件结尾对齐,以保证HASH部分包括文件的结尾。
当然,因为没有对全文件做HASH,所以没有被HASH到的部分如果有修改,是不会被发现的,但是对我的需求来说基本不会有这种情况,所以不要紧,但是这样可以让HASH速度大大加快,特别是对那些几个G的大文件(不许联想,我说的是操作系统的安装ISO镜像文件之类)。
以上是关于快速文件hash的主要内容,如果未能解决你的问题,请参考以下文章
海量数据处理:Hash映射 + Hash_map统计 + 堆/快速/归并排序
如何使基于Media Foundation的播放打开并快速查找moov结尾的MP4 HTTP文件?