通過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

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