在做項目中要求獲取文件的hash並按照hash命名存儲文件,整理了一個幫助類,可以獲得文件、文件流、字符串的hash值,詳情請看代碼
package com.mgtv.media.vrs.util;
import java.io.*;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
/**
* @author :****@mgtv.com
* @date :Created in 2020/3/26 19:13
*/
public class MD5Util {
private static final char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f'};
public static void main(String[] args) {
//此處我測試的是我本機jdk源碼文件的MD5值
String filePath = "F:\\tmp\\clips\\c1\\subtitle\\2020\\04\\02_5164686\\20200402150211504_164.srt";
String md5Hashcode2 = MD5Util.getFileMD5(new File(filePath));
System.out.println("MD5Util2計算文件md5值爲:" + md5Hashcode2);
System.out.println("MD5Util2計算文件md5值的長度爲:" + md5Hashcode2.length());
}
/**
* Get MD5 of a file (lower case)
*
* @return empty string if I/O error when get MD5
*/
public static String getFileMD5(File file) {
FileInputStream in = null;
try {
in = new FileInputStream(file);
FileChannel ch = in.getChannel();
return MD5(ch.map(FileChannel.MapMode.READ_ONLY, 0, file.length()));
} catch (FileNotFoundException e) {
return "";
} catch (IOException e) {
return "";
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
// 關閉流產生的錯誤一般都可以忽略
}
}
}
}
/**
* java獲取文件的md5值
*
* @param fis 輸入流
* @return
*/
public static String getFileMD5(InputStream fis) {
try {
//拿到一個MD5轉換器,如果想使用SHA-1或SHA-256,則傳入SHA-1,SHA-256
MessageDigest md = MessageDigest.getInstance("MD5");
//分多次將一個文件讀入,對於大型文件而言,比較推薦這種方式,佔用內存比較少。
byte[] buffer = new byte[1024];
int length = -1;
while ((length = fis.read(buffer, 0, 1024)) != -1) {
md.update(buffer, 0, length);
}
fis.close();
//轉換並返回包含16個元素字節數組,返回數值範圍爲-128到127
byte[] md5Bytes = md.digest();
return byteToHex(md5Bytes);
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/**
* MD5校驗字符串
*
* @param s String to be MD5
* @return 'null' if cannot get MessageDigest
*/
public static String getStringMD5(String s) {
MessageDigest mdInst;
try {
// 獲得MD5摘要算法的 MessageDigest 對象
mdInst = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return "";
}
byte[] btInput = s.getBytes();
// 使用指定的字節更新摘要
mdInst.update(btInput);
// 獲得密文
byte[] md = mdInst.digest();
// 把密文轉換成十六進制的字符串形式
int length = md.length;
char str[] = new char[length * 2];
int k = 0;
for (byte b : md) {
str[k++] = hexDigits[b >>> 4 & 0xf];
str[k++] = hexDigits[b & 0xf];
}
return new String(str);
}
@SuppressWarnings("unused")
private static String getSubStr(String str, int subNu, char replace) {
int length = str.length();
if (length > subNu) {
str = str.substring(length - subNu, length);
} else if (length < subNu) {
// NOTE: padding字符填充在字符串的右側,和服務器的算法是一致的
str += createPaddingString(subNu - length, replace);
}
return str;
}
private static String createPaddingString(int n, char pad) {
if (n <= 0) {
return "";
}
char[] paddingArray = new char[n];
Arrays.fill(paddingArray, pad);
return new String(paddingArray);
}
/**
* 計算MD5校驗
*
* @param buffer
* @return 空串,如果無法獲得 MessageDigest實例
*/
private static String MD5(ByteBuffer buffer) {
String s = "";
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(buffer);
byte tmp[] = md.digest(); // MD5 的計算結果是一個 128 位的長整數,
s = byteToHex(tmp);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return s;
}
private static String byteToHex(byte[] tmp) {
String s = "";
// 用字節表示就是 16 個字節
char str[] = new char[16 * 2]; // 每個字節用 16 進製表示的話,使用兩個字符,
// 所以表示成 16 進制需要 32 個字符
int k = 0; // 表示轉換結果中對應的字符位置
for (int i = 0; i < 16; i++) { // 從第一個字節開始,對 MD5 的每一個字節
// 轉換成 16 進制字符的轉換
byte byte0 = tmp[i]; // 取第 i 個字節
str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字節中高 4 位的數字轉換, >>>,
// 邏輯右移,將符號位一起右移
str[k++] = hexDigits[byte0 & 0xf]; // 取字節中低 4 位的數字轉換
}
s = new String(str); // 換後的結果轉換爲字符串
return s;
}
}