通过python利用哈希值实现比较两个文件的一致性

背景

近来学习到python的内置函数hash(),深入发现通过python的哈希值可以做很多的事情,最典型的可能就是文件加密了,在我们现实生活中大约有如下一些用途:

  • 加密网站注册用户的密码。
  • 网站用户上传图片 / 文件后,计算出MD5值作为文件名。(MD5可以保证唯一性)
  • key-value数据库中使用MD5值作为key。
  • 比较两个文件是否相同。(大家在下载一些资源的时候,就会发现网站提供了MD5值,就是用来检测文件是否被篡改)
    本文就是通过python简单实现如何比较两个文件是否相等?

实现原理

散列函数(或散列算法,又称哈希函数,英语:Hash Function)是一种从任何一种数据中创建小的数字“指纹”的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定下来。该函数将数据打乱混合,重新创建一个叫做散列值(hash values,hash codes,hash sums,或hashes)的指纹。散列值通常用一个短的随机字母和数字组成的字符串来代表。好的散列函数在输入域中很少出现散列冲突。在散列表和数据处理中,不抑制冲突来区别数据,会使得数据库记录更难找到。
加密散列函数,是散列函数的一种。它被认为是一种单向函数,也就是说极其难以由散列函数输出的结果,回推输入的资料是什么。这样的单向函数被称为“现代密码学的驮马”。这种散列函数的输入资料,通常被称为讯息(message),而它的输出结果,经常被称为讯息摘要(message digest)或摘要(digest)。它的过程如下:
加密散列函数原理

具体实现

MD5

MD5的全称是Message-Digest Algorithm 5(信息-摘要算法)。128位长度。目前MD5是一种不可逆算法。具有很高的安全性。它对应任何字符串都可以加密成一段唯一的固定长度的代码。

SHA1

SHA1的全称是Secure Hash Algorithm(安全哈希算法) 。SHA1基于MD5,加密后的数据长度更长,它对长度小于264的输入,产生长度为160bit的散列值。比MD5多32位。
因此,比MD5更加安全,但SHA1的运算速度就比MD5要慢了。

我们将演示使用MD5散列算法来hash文件。 我们不会一次性提取全部文件数据,因为一些文件非常大,会很消耗内存甚至一次性放不下。将文件分割成小块读取将使处理过程高效地使用内存。
在Python中内置的 hashlib 模块就包括了 md5 和 sha1 算法。而且使用起来也极为方便,我们使用md5算法来实现我们比较文件一致性的功能,我们会使用update()方法来对这个对象填充任意的字符串。在任何时候你都可以使用digest()或hexdigest()方法问它要目前为止填充的字符串的摘要。我们需要了解以下几个函数:

hash.update(arg)

用字符串arg更新哈希对象。重复的调用等同於单次调用所有参数的连接:m.update(a); m.update(b) 相当于m.update(a+b)。

hash.digest()

返回目前为止传递给update()方法的字符串的摘要。它是一个具有digest_size个字节的字符串,其中可能包含非ASCII 字符,包括空字节。

hash.hexdigest()

类似digest(),但是返回的摘要的字符串的长度翻倍,且只包含十六进制数字。这可用于在电子邮件或其它非二进制环境中安全交换数据。

代码

# !/usr/bin/env python
# -*- coding: utf-8 -*-
# Time: 17-11-29 下午10:26
# Author: sty
# File: compare_file.py


import hashlib

def get_file_md5(f):
    m = hashlib.md5()
    while True:
        #如果不用二进制打开文件,则需要先编码
        #data = f.read(1024).encode('utf-8')
        data = f.read(1024)  #将文件分块读取
        if not data:
            break
        m.update(data)
    return m.hexdigest()

#将file2文件写入改动了一个位数的数据
txt1 = '你好么?我可以用下面这段代码验证一下:'
txt2 = '你好么?我可以用下面这段代码验证一下:1'
with open('1.txt', 'w', encoding='utf-8') as f1, open('2.txt', 'w', encoding='utf-8') as f2:
    f1.write(txt1)
    f2.write(txt2)

with open('1.txt', 'rb') as f1, open('2.txt', 'rb') as f2:
    file1_md5 = get_file_md5(f1)
    file2_md5 = get_file_md5(f2)
    print('file1_md5:',file1_md5)
    print('file2_md5:',file2_md5)
    if file1_md5 != file2_md5:
        print('file has changed')
    else:
        print('file not changed')

在代码中,我们通过将两段字符串txt1,txt2来模拟文件的改动,分别写入1.txt,2.txt,然后我们将两个文件分别读取,计算它们的MD5值,通过比较MD5值便可以知道它们是否一致。
需要注意
1.是文件打开方式一定要是二进制方式,既打开文件时使用b模式,否则Hash计算是基于文本的那将得到错误的文件Hash,如果不用’rb’去读的话,而用’r’去读的话,我们读取的是uncode的编码,然后我们将读取到的内容编码成’utf-8’,即encode(‘utf-8’),然后进行MD5计算也是可以的。
2.为了避免读入的文件过大,我们是分块读取的。

参考资料:

http://www.cnblogs.com/thinkingfor/archive/2010/09/13/1824766.html
http://www.cnblogs.com/the4king/archive/2012/02/06/2340660.html
http://usyiyi.cn/documents/python_278/library/hashlib.html
https://www.wikiwand.com/zh/%E5%AF%86%E7%A2%BC%E9%9B%9C%E6%B9%8A%E5%87%BD%E6%95%B8

转载请注明出处:
CSDN:楼上小宇_home:http://blog.csdn.net/sty945
简书:楼上小宇:http://www.jianshu.com/u/1621b29625df

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章