Java关于MD5文件校验问题处理

 更新时间:2026年03月30日 09:42:43   作者:Pisces_224  
文章主要介绍了Java获取文件MD5值的五种方法,包括原始读入内存、分多次读入、使用字节数组转十六进制字符串、利用commons-codec包等,并解释了MD5算法原理、用途及安全性,最后提供了验证生成MD5值正确性的方法

前言

JAVA中获取文件MD5值的四种方法其实都很类似,因为核心都是通过JAVA自带的MessageDigest类来实现。

获取文件MD5值主要分为三个步骤,第一步获取文件的byte信息,第二步通过MessageDigest类进行MD5加密,第三步转换成16进制的MD5码值。

什么是MD5算法

MD5讯息摘要演算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码杂凑函数,可以产生出一个128位元(16位元组)的散列值(hash value),用于确保信息传输完整一致。

原理

MD5是一种不可逆的算法,是一种散列函数,使用的是hash算法。输入任意长度的信息,经过处理,输出为128位的信息(数字指纹),不同的输入得到的不同的结果(唯一性)。

在计算过程中原文的部分信息是丢失了的。所以不能从密文(散列值)反过来得到原文,即没有解密算法。

MD5相当于超损压缩。

MD5用途

1.防止被篡改:

1)比如发送一个电子文档,发送前,我先得到MD5的输出结果a。然后在对方收到电子文档后,对方也得到一个MD5的输出结果b。如果a与b一样就代表中途未被篡改。

2)比如我提供文件下载,为了防止不法分子在安装程序中添加木马,我可以在网站上公布由安装文件得到的MD5输出结果。

3)SVN在检测文件是否在CheckOut后被修改过,也是用到了MD5.

2.防止直接看到明文:

  • 现在很多网站在数据库存储用户的密码的时候都是存储用户密码的MD5值。这样就算不法分子得到数据库的用户密码的MD5值,也无法知道用户的密码。(比如在UNIX系统中用户的密码就是以MD5(或其它类似的算法)经加密后存储在文件系统中。
  • 当用户登录的时候,系统把用户输入的密码计算成MD5值,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。
  • 这不但可以避免用户的密码被具有系统管理员权限的用户知道,而且还在一定程度上增加了密码被破解的难度。)

3.防止抵赖(数字签名):

  • 这需要一个第三方认证机构。例如A写了一个文件,认证机构对此文件用MD5算法产生摘要信息并做好记录。
  • 若以后A说这文件不是他写的,权威机构只需对此文件重新产生摘要信息,然后跟记录在册的摘要信息进行比对,相同的话,就证明是A写的了。这就是所谓的“数字签名”。

MD5安全性

普遍认为MD5是很安全,因为暴力.破.解的时间是一般人无法接受的。实际上如果把用户的密码MD5处理后再存储到数据库,其实是很不安全的。因为用户的密码是比较短的,而且很多用户的密码都使用生日,手机号码,身份证号码,电话号码等等。或者使用常用的一些吉利的数字,或者某个英文单词。

如果我把常用的密码先MD5处理,把数据存储起来,然后再跟你的MD5结果匹配,这时我就有可能得到明文。

现在大多数网站密码的策略是强制要求用户使用数字大小写字母的组合的方式提高用户密码的安全度。

方法

方法一

较为原始,将文件一次性读入内存,然后通过MessageDigest进行MD5加密,最后再手动将其转换为16进制的MD5值。

private final static String[] strHex = { "0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };

    public static String getMD5One(String path) {
        StringBuffer sb = new StringBuffer();
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] b = md.digest(FileUtils.readFileToByteArray(new File(path)));
            for (int i = 0; i < b.length; i++) {
                int d = b[i];
                if (d < 0) {
                    d += 256;
                }
                int d1 = d / 16;
                int d2 = d % 16;
                sb.append(strHex[d1] + strHex[d2]);
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

方法二

借助了Integer类的方法实现16进制的转换,比方法一更简洁一些。

PS:JAVA中byte是有负数的,代码中&0xff的操作与计算机中数据存储的原理有关,即负数存储的是二进制的补码。

public static String getMD5Two(String path) {
        StringBuffer sb = new StringBuffer("");
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(FileUtils.readFileToByteArray(new File(path)));
            byte b[] = md.digest();
            int d;
            for (int i = 0; i < b.length; i++) {
                d = b[i];
                if (d < 0) {
                    d = b[i] & 0xff;
                    // 与上一行效果等同
                    // i += 256;
                }
                if (d < 16)
                    sb.append("0");
                sb.append(Integer.toHexString(d));
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

方法三

本方法在读入文件信息上有点不同。这里是分多次将一个文件读入,对于大型文件而言,比较推荐这种方式,占用内存比较少。

步骤三则是通过BigInteger类提供的方法进行16进制的转换。

public static String getMD5Three(String path) {
        BigInteger bi = null;
        try {
            byte[] buffer = new byte[8192];
            int len = 0;
            MessageDigest md = MessageDigest.getInstance("MD5");
            File f = new File(path);
            FileInputStream fis = new FileInputStream(f);
            while ((len = fis.read(buffer)) != -1) {
                md.update(buffer, 0, len);
            }
            fis.close();
            byte[] b = md.digest();
            bi = new BigInteger(1, b);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bi.toString(16);
    }

方法四

通过调用 字节数组转十六进制字符串的方法 实现(跟方法3差不多)

public static String getMD5Four(String filePath) {

        try {
            InputStream fis = new FileInputStream(filePath); // FileNotFoundException
            MessageDigest md = MessageDigest.getInstance("MD5"); // NoSuchAlgorithmException
            byte[] buffer = new byte[1024];
            int length = -1;
            while ((length = fis.read(buffer, 0, 1024)) != -1) {  // IO exception
                md.update(buffer, 0, length);
            }
            fis.close();
            // 转换并返回包含16个元素字节数组,返回数值范围为-128到127
            byte[] md5Bytes = md.digest();
            // 方法2 使用bigInteger
//            BigInteger bigInteger = new BigInteger(1, md5Bytes);
//            return bigInteger.toString(16);
            // 方法3  使用字节数组转十六进制字符串
            String strMd5 = bytesToHexStr(md5Bytes);
            return strMd5;


        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return "";
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return "";
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 字节数组转十六进制字符串
     * @param b 字节数组
     * @return 十六进制字符串
     */
    public static String bytesToHexStr(byte[] b) {
        StringBuilder strBuilder = new StringBuilder();
        String strTemp = "";
        for (int n = 0; n < b.length; ++n) {
            strTemp = (Integer.toHexString(b[n] & 0XFF));
            if (strTemp.length() == 1) {
                strBuilder.append("0").append(strTemp);
            } else {
                strBuilder.append(strTemp);
            }
        }
        return strBuilder.toString();
    }

方法五

最简单~

JAVA自带的commons-codec包就提供了获取16进制MD5值的方法。其底层实现上,也是分多次将一个文件读入,类似方法三、四

DigestUtils.md5Hex(new FileInputStream(path));

另外,如何知道自己生成的文件md5值是否正确?

cmd 输入 powershell 切入到powershell面板

certutil -hashfile “./xxx.txt” MD5    # (MD5需大写)

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • springboot集成ES实现磁盘文件全文检索的示例代码

    springboot集成ES实现磁盘文件全文检索的示例代码

    这篇文章主要介绍了springboot集成ES实现磁盘文件全文检索的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • Java中基于DeferredResult的异步服务详解

    Java中基于DeferredResult的异步服务详解

    这篇文章主要介绍了Java中基于DeferredResult的异步服务详解,DeferredResult字面意思是"延迟结果",它允许Spring MVC收到请求后,立即释放(归还)容器线程,以便容器可以接收更多的外部请求,提升吞吐量,需要的朋友可以参考下
    2023-12-12
  • Java中throws 与 throw 的区别与用法示例详解

    Java中throws 与 throw 的区别与用法示例详解

    本文给大家介绍Java中throws与throw的区别与用法示例详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2025-09-09
  • Java多文件以ZIP压缩包导出的实现方法

    Java多文件以ZIP压缩包导出的实现方法

    这篇文章主要为大家详细介绍了Java多文件以ZIP压缩包导出的实现方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07
  • SpringBoot使用@ResponseBody返回图片的实现

    SpringBoot使用@ResponseBody返回图片的实现

    这篇文章主要介绍了SpringBoot使用@ResponseBody返回图片的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • Java SimpleDateFormat线程安全问题原理详解

    Java SimpleDateFormat线程安全问题原理详解

    这篇文章主要介绍了Java SimpleDateFormat线程安全问题原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • java中实现视频处理以及播放功能代码详解

    java中实现视频处理以及播放功能代码详解

    这篇文章主要给大家介绍了关于java中实现视频处理以及播放功能的相关资料,最近要实现一套音视频播放程序,所以这里给大家总结下,需要的朋友可以参考下
    2023-09-09
  • Java 多线程实例详解(三)

    Java 多线程实例详解(三)

    本文主要介绍 java 线程安全的知识,这里整理了相关资料及实现示例代码,有兴趣的小伙伴可以参考下
    2016-09-09
  • Netty核心功能之数据容器ByteBuf详解

    Netty核心功能之数据容器ByteBuf详解

    这篇文章主要为大家介绍了Netty核心功能之数据容器ByteBuf详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • SpringBoot优化连接数的方法详解

    SpringBoot优化连接数的方法详解

    SpringBoot开发最大的好处是简化配置,内置了Tomcat,下面这篇文章主要给大家介绍了关于SpringBoot优化连接数的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-06-06

最新评论