package org.sxkj.common.utils.file; import org.springframework.util.StringUtils; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * 文件名SHA-256算法生成hash值 */ public class FileNameHarsher { /** * 根据文件路径生成唯一的 SHA-256 哈希值 * * @param filePath 文件路径 * @return 64位十六进制哈希字符串 * @throws RuntimeException 如果系统不支持 SHA-256 算法 */ public static String generateFileHash(String filePath) { try { if(StringUtils.isEmpty(filePath)){ return ""; } // 1. 提取文件名(最后一个 / 后面的部分) String fileName = extractFileName(filePath); // 2. 获取 SHA-256 消息摘要实例 MessageDigest digest = MessageDigest.getInstance("SHA-256"); // 3. 将文件名转换为字节数组(UTF-8编码) byte[] encodedHash = digest.digest(fileName.getBytes()); // 4. 将字节数组转换为十六进制字符串 return bytesToHex(encodedHash); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("系统不支持 SHA-256 哈希算法", e); } } /** * 从文件路径中提取文件名(最后一个 / 后面的部分) * * @param filePath 完整文件路径 * @return 文件名部分 */ private static String extractFileName(String filePath) { if (filePath == null || filePath.isEmpty()) { return ""; } // 处理 Windows 路径分隔符(将 \ 替换为 /) String normalizedPath = filePath.replace('\\', '/'); // 查找最后一个 / 的位置 int lastIndex = normalizedPath.lastIndexOf('/'); // 如果找到 /,返回它后面的子字符串 if (lastIndex >= 0 && lastIndex < normalizedPath.length() - 1) { return normalizedPath.substring(lastIndex + 1); } // 没有找到 /,直接返回原路径 return normalizedPath; } /** * 将字节数组转换为十六进制字符串 * * @param hash 字节数组 * @return 十六进制字符串 */ private static String bytesToHex(byte[] hash) { StringBuilder hexString = new StringBuilder(2 * hash.length); for (byte b : hash) { String hex = Integer.toHexString(0xff & b); if (hex.length() == 1) { hexString.append('0'); } hexString.append(hex); } return hexString.toString(); } }