如何使用Java計算修改文件的MD5值

什麼是 MD5 ?

MD5(Message Digest Algorithm,信息摘要算法),一種被廣泛使用的密碼散列函數,可以產生出一個128位(16字節)的散列值(hash value),用於確保信息傳輸完整一致。它後面這個數字 5 是因為它是為瞭取代 MD4 而發明的。簡單的理解,它的作用就是給文件一個唯一標識。 如果我們修改瞭一個文件的擴展名,文件可能會打不開,但是對於 MD5 來說,並沒有什麼改變。所以對於一個文件,進行任何的重新命名對於md5校驗都是沒有用的。

MD5 的應用

這裡隻提幾點我見過的比較頻繁的應用情況。

下載文件校驗

因為網絡並不是完美的,下載大文件的過程中可能會出錯(小文件也會,但是通常越大的文件幾率越大),這是很正常的現象,網絡出現波動是很正常的。所以,通常有些軟件的jar或開發工具會額外提供一個文件的md5值下載(因為它很小,通常認為是不會出錯的),用於用戶校驗文件是否下載錯誤。但是現在網絡也是越來越好瞭,基本上不會錯誤。(所以我沒有使用過,如果用戶的網絡環境不是很好,下載完畢一定要校驗一下,免得出錯。)

上傳文件

相比之下,md5值上傳文件的應用范圍就更大瞭。這裡主要的用途是為瞭文件去重和文件過濾

文件去重

我們知道用戶上傳的文件中,一般都是有很多重復的,如最近流行的電影、電視劇、遊戲或者其它的流行資源。其實它們占據瞭用戶上傳文件的很大一部分,所以對於同一份資源,隻需要存儲一份就可以瞭。試想一下,一萬個用戶(一萬可能都少瞭)上傳瞭同一份 4GB 的電影,那麼總共需要磁盤容量:4*10000 GB。如果隻是上傳一份,對於其它用戶的上傳隻是在本地計算文件的 md5值 ,如果相同就認為是同一個文件,那麼就隻需要 4GB 空間就足夠瞭(當然,這裡忽略瞭記錄信息的空間大小,但是相比於文件本身的大小,這些信息還是很小的)。大傢可以想一下,這樣對於空間的節約是多麼巨大的。
大傢生活中,應該經常用到,上傳一個幾個 GB 的大文件,居然幾秒鐘就完成瞭,但是稍微有點網絡知識的都知道,網絡的上傳速率是小於下載速率的(這隻是對於終端用戶來說),下載都達不到的速度,上傳更是不可能的。所以,它應該隻是進行瞭一個文件md5值的計算過程,根據計算的結果,如果有就不上傳,隻是記錄一下用戶擁有這個文件而已。如果沒有的話,就老老實實上傳,當然瞭,這個過程通常很慢。

文件過濾

有一些文件涉及到版權和政策的關系,是不允許用戶上傳的。所以,對於用戶上傳文件也會進行校驗,然後和後臺的黑名單匹配(應該是這樣的),如果匹配成功的話,那麼文件是無法上傳或者上傳的文件已經被處理掉瞭。這樣方法的效率很高的,通常用戶所謂的亂改名操作是完全沒有用的。所以,用戶一定要遵守政策和相關平臺的規定。

修改文件的 MD5 值

一般情況下,隻要改變瞭文件的二進制內容,文件的md5值一定會改變的。通常有利用壓縮文件的方式,將多個文件壓縮上傳的方式,這樣壓縮文件的 md5值也會改變,但是有的平臺也是可以解壓文件的,所以這樣也不是萬能的。但是通過程序修改和還原文件的二進制數據還是比較容易地,使用Java的流幾乎可以對與文件進行任何操作(例如對於文件的每個字節進行加密,這樣想還原這個文件就是很難的,或者隻是加密一段或者首先創建一個文件,先向文件寫入一段固定的數字,再寫入相關文件的數據,這樣也是很不錯的方法。)。對於文件來說,我們可以簡單地把它看出是一連串連續地二進制流(邏輯上),將它合並(增加)或者截斷(減少)是很簡單地操作,這裡就是簡單的涉及文件 和 IO流的知識瞭。

我上次寫瞭一個關於文件合並操作的程序,可以將文本、圖片和視頻進行合並,如果感興趣,可以參考一下:文件合並(圖片+視頻),修改md5值,隱藏文件

一個簡單的計算 md5 的程序

這個程序是Java網絡編程上面的,這裡去掉瞭線程,簡化瞭一下操作,反正隻是用於計算md5值,不需要用戶的其它操作。

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.xml.bind.DatatypeConverter;

public class TestMD5 {
	public static void main(String[] args){
		for (String filepath : args) {
			String md5 = computeMD5(new File(filepath));
			System.out.println(md5);
		}
	}
	
	
	private static String computeMD5(File file) {
		DigestInputStream din = null;
		try {
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			//第一個參數是一個輸入流
			din = new DigestInputStream(new BufferedInputStream(new FileInputStream(file)), md5);
			
			byte[] b = new byte[1024];
			while (din.read(b) != -1);
		
			byte[] digest = md5.digest();
			
			StringBuilder result = new StringBuilder(file.getName());
			result.append(": ");
			result.append(DatatypeConverter.printHexBinary(digest));
			return result.toString();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (din != null) {
					din.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}
}

運行結果

在這裡插入圖片描述

修改 MD5 值

這裡有兩個圖片,對它們進行合並,註意我這裡的合並,不是通常所說的文件合並(例如合成九宮格圖片),而是將文件的二進制數據合並。

在這裡插入圖片描述

先計算文件的 md5 值,註意下面的 Ahusky.jpeg 是上面的 husky.jpeg 的重命名,可以看出來對於md5值來說並沒有變化,所以這是同一個文件。

在這裡插入圖片描述

然後將文件合並,這裡用到的程序是我上面關於文件合並裡面介紹的。可以進入瞭解詳情,這裡不再介紹瞭。

在這裡插入圖片描述

計算合並後文件的 md5 值

在這裡插入圖片描述

到此這篇關於如何使用Java計算修改文件的MD5值的文章就介紹到這瞭,更多相關Java計算修改文件的MD5值內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: