package org.sxkj.common.utils; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5Util { /** * 计算文件的“16位MD5”哈希值 (截取32位MD5的中间16位) * * @param file 要计算MD5的文件 * @return 文件的“16位MD5”哈希字符串,如果发生错误或无法生成32位MD5则返回null */ public static String get16BitMD5Checksum(File file) { String fullMD5 = getFullMD5Checksum(file); if (fullMD5 != null && fullMD5.length() == 32) { // 截取第9到第24位 (索引8到23) return fullMD5.substring(8, 24); } return null; } /** * 计算文件的标准32位MD5哈希值 * * @param file 要计算MD5的文件 * @return 文件的32位MD5哈希字符串,如果发生错误则返回null */ public static String getFullMD5Checksum(File file) { if (file == null || !file.exists() || !file.isFile()) { System.err.println("Invalid file provided for MD5 calculation."); return null; } try (InputStream fis = new FileInputStream(file)) { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] buffer = new byte[8192]; // 缓冲区可以大一点,例如8KB int bytesRead; while ((bytesRead = fis.read(buffer)) != -1) { md.update(buffer, 0, bytesRead); } byte[] digest = md.digest(); StringBuilder sb = new StringBuilder(); for (byte b : digest) { sb.append(String.format("%02x", b)); } return sb.toString(); } catch (IOException | NoSuchAlgorithmException e) { e.printStackTrace(); return null; } } public static String getMD5Checksum(File file) { try (InputStream fis = new FileInputStream(file)) { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = fis.read(buffer)) != -1) { md.update(buffer, 0, bytesRead); } byte[] digest = md.digest(); StringBuilder sb = new StringBuilder(); for (byte b : digest) { sb.append(String.format("%02x", b)); } return sb.toString(); } catch (IOException | NoSuchAlgorithmException e) { e.printStackTrace(); return null; } } /** * 【核心方法】从任意输入流计算 MD5 校验和。 * @param is 输入流 * @return 32位的十六进制 MD5 字符串 * @throws NoSuchAlgorithmException 如果 MD5 算法不可用 * @throws IOException 如果流读取失败 */ private static String calculateMD5(InputStream is) throws NoSuchAlgorithmException, IOException { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] buffer = new byte[8192]; // 8KB 缓冲区 int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { md.update(buffer, 0, bytesRead); } byte[] digest = md.digest(); StringBuilder sb = new StringBuilder(); for (byte b : digest) { sb.append(String.format("%02x", b)); } return sb.toString(); } /** * 【新增方法】从网络 URL 计算文件的 MD5 校验和。 * @param urlString 文件的网络地址 * @return 32位的十六进制 MD5 字符串,如果出错则返回 null */ public static String getMD5ChecksumFromUrl(String urlString) { try { URL url = new URL(urlString); // try-with-resources 确保网络流被关闭 try (InputStream is = url.openStream()) { return calculateMD5(is); } } catch (IOException | NoSuchAlgorithmException e) { // MalformedURLException 是 IOException 的子类,所以会被捕获 e.printStackTrace(); return null; } } public static String getMD5Checksum(String input) { try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] bytes = input.getBytes(); md.update(bytes); byte[] digest = md.digest(); StringBuilder sb = new StringBuilder(); for (byte b : digest) { sb.append(String.format("%02x", b)); } return sb.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } } }