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

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

作者: 楼上小宇 | 来源:发表于2017-11-30 08:42 被阅读581次

    背景

    近来学习到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

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/bzvmbxtx.html