自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java 如何校驗兩個文件內(nèi)容是相同的?

開發(fā) 后端
等合并代碼的時候發(fā)現(xiàn)這位同學(xué)居然用文件名稱相同和文件大小相同作為兩個文件相同的依據(jù)。這種條件判斷靠譜嗎?

[[437709]]

今天做文件上傳功能,需求要求文件內(nèi)容相同的不能重復(fù)上傳。感覺這個需求挺簡單的就交給了一位剛?cè)胄械男峦瑢W(xué)。等合并代碼的時候發(fā)現(xiàn)這位同學(xué)居然用文件名稱相同和文件大小相同作為兩個文件相同的依據(jù)。這種條件判斷靠譜嗎?

從概率上來說遇到兩個文件名稱和大小都一樣的概率確實太小了。這種判斷放在生產(chǎn)環(huán)境中也可以穩(wěn)定的跑上一陣子,不過即使再低的可能性也是有可能的,如果能做到100%就好了。

文件摘要校驗

我相信同學(xué)們都下載過一些好心人開發(fā)的小工具,有些小工具會附帶一個校驗器讓你校驗附帶提供的checksum值,防止有人惡意篡改小工具,保證小工具可以放心使用。

文件Hash校驗

如果兩個文件的內(nèi)容相同,那么它們的摘要應(yīng)該是相同的。這個原理能不能幫助我們鑒定兩個文件是否相同呢?

Java實現(xiàn)文件摘要

帶著這個疑問,我寫了一個文件摘要提取工具類:

  1. /** 
  2.  * 提取文件 checksum  
  3.  * 
  4.  * @param path      文件全路徑 
  5.  * @param algorithm  算法名 例如 MD5、SHA-1、SHA-256等 
  6.  * @return  checksum 
  7.  * @throws NoSuchAlgorithmException the no such algorithm exception 
  8.  * @throws IOException              the io exception 
  9.  */ 
  10. public static String extractChecksum(String path, String algorithm) throws NoSuchAlgorithmException, IOException { 
  11.     // 根據(jù)算法名稱初始化摘要算法 
  12.     MessageDigest digest = MessageDigest.getInstance(algorithm); 
  13.     // 讀取文件的所有比特 
  14.     byte[] fileBytes = Files.readAllBytes(Paths.get(path)); 
  15.     // 摘要更新 
  16.     digest.update(fileBytes); 
  17.     //完成哈希摘要計算并返回特征值 
  18.     byte[] digested = digest.digest(); 
  19.     // 進行十六進制的輸出 
  20.     return HexUtils.toHexString(digested); 

接下來做幾組對照試驗來證明猜想。

內(nèi)容不變

首先要證明一個文件在內(nèi)容不變的情況下摘要是否有變化,多次執(zhí)行下面的代碼,斷言始終都是true。

  1. String path = "C:\\Users\\s1\\IdeaProjects\\demo\\src\\main\\resources\\application.yml"
  2.  
  3. String checksum = extractChecksum(path, "SHA-1"); 
  4.  
  5. String hash = "6bf4d6c101b4a7821226d3ec1f8d778a531bf265"
  6.  
  7. Assertions.assertEquals(hash,checksum); 

而且我把文件名改成application-dev.yml,甚至application-dev.txt摘要都是相同的。我又把yml文件的內(nèi)容作了改動,斷言就false了。這證明了單個文件的情況下,內(nèi)容不變,hash是不變的。

文件復(fù)制

我把yml文件復(fù)制了一份,改了文件名稱和類型,不改變內(nèi)容并存到了另一個目錄中,來測試一下它們的摘要是否有變化。

  1. String path1 = "C:\\Users\\s1\\IdeaProjects\\demo\\src\\main\\resources\\application.yml"
  2.  
  3. String path2 = "C:\\Users\\s1\\IdeaProjects\\demo\\src\\main\\resources\\templates\\application-dev.txt"
  4.  
  5. String checksum1 = extractChecksum(path1, "SHA-1"); 
  6.  
  7. String checksum2 = extractChecksum(path2, "SHA-1"); 
  8.  
  9. String hash = "6bf4d6c101b4a7821226d3ec1f8d778a531bf265"
  10.  
  11. Assertions.assertEquals(hash,checksum1); 
  12.  
  13. Assertions.assertEquals(hash,checksum2); 

結(jié)果斷言通過,不過改變了其中一個文件的內(nèi)容后斷言就不通過了。

新建空文件

這里的新建空文件指的是沒有進行任何操作的新建的空文件。

新建的空文件會根據(jù)特定的算法返回一個固定值,比如SHA-1算法下的空文件值是:

  1. da39a3ee5e6b4b0d3255bfef95601890afd80709 

結(jié)論

通過實驗證明了:

在相同算法下,任何新建空文件的摘要值都是固定的。

任何兩個內(nèi)容相同的文件的摘要值都是相同的,和路徑、文件名、文件類型無關(guān)。

文件的摘要值會隨著文件內(nèi)容的改變而改變。

文件摘要運用

根據(jù)上面的結(jié)論,文件摘要是可以防止同樣內(nèi)容的文件重復(fù)提交的, 存儲的時候不但要存儲文件的路徑,還要存儲文件的摘要值,可能需要注意新建空文件的的固定摘要問題。另外在Java12中提供了新的API來處理文件內(nèi)容重復(fù)問題,有興趣的可以研究一下。文件摘要除了防篡改和去重之外,你知道還有其它什么用途嗎?歡迎同學(xué)們留言討論。

本文轉(zhuǎn)載自微信公眾號「碼農(nóng)小胖哥」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系碼農(nóng)小胖哥公眾號。

 

責任編輯:武曉燕 來源: 碼農(nóng)小胖哥
相關(guān)推薦

2010-08-23 17:34:06

DHCP協(xié)議

2023-10-04 20:03:46

GOkeyvalue

2011-08-29 18:17:58

Ubuntu

2018-07-02 10:07:08

2020-08-14 08:13:49

列表差異編程

2022-06-17 09:46:51

Chrome 102Chrome瀏覽器

2021-05-07 08:03:05

JS動態(tài)合并

2010-07-02 12:26:51

LEACH協(xié)議

2009-06-30 09:37:02

對象比較Java

2009-07-15 18:29:22

Jython應(yīng)用

2012-05-17 15:28:54

云計算

2020-11-13 07:16:09

線程互斥鎖死循環(huán)

2023-03-31 07:31:28

SliceGolang

2013-08-09 10:05:41

亞馬遜團隊

2013-07-05 10:52:07

程序員結(jié)對編程

2015-02-05 09:54:13

程序員

2010-07-17 00:50:12

batch Telne

2010-07-17 00:59:44

cmd Telnet

2011-07-05 16:13:18

2010-07-25 14:31:54

Telnet程序
點贊
收藏

51CTO技術(shù)棧公眾號