Java如何校验两个文件内容是相同的?

举报
码农小胖哥 发表于 2022/03/31 23:58:00 2022/03/31
【摘要】 今天做文件上传功能,需求要求文件内容相同的不能重复上传。感觉这个需求挺简单的就交给了一位刚入行的新同学。等合并代码的时候发现这位同学居然用文件名称相同和文件大小相同作为两个文件相同的依据。这种条件判断靠谱吗? 从概率上来说遇到两个文件名称和大小都一样的概率确实太小了。这种判断放在生产环境中也可以稳定的跑上一阵子,不过即使再低...

f01405dd832f746dd9c9e28305c0f144.gif

今天做文件上传功能,需求要求文件内容相同的不能重复上传。感觉这个需求挺简单的就交给了一位刚入行的新同学。等合并代码的时候发现这位同学居然用文件名称相同和文件大小相同作为两个文件相同的依据。这种条件判断靠谱吗?

从概率上来说遇到两个文件名称和大小都一样的概率确实太小了。这种判断放在生产环境中也可以稳定的跑上一阵子,不过即使再低的可能性也是有可能的,如果能做到100%就好了。

文件摘要校验

我相信同学们都下载过一些好心人开发的小工具,有些小工具会附带一个校验器让你校验附带提供的checksum值,防止有人恶意篡改小工具,保证小工具可以放心使用。

351de650015ebe594561e968c7fc21fd.png 文件Hash校验

如果两个文件的内容相同,那么它们的摘要应该是相同的。这个原理能不能帮助我们鉴定两个文件是否相同呢?

Java实现文件摘要

带着这个疑问,我写了一个文件摘要提取工具类:


   
  1. /**
  2.      * 提取文件 checksum 
  3.      *
  4.      * @param path      文件全路径
  5.      * @param algorithm  算法名 例如 MD5、SHA-1、SHA-256等
  6.      * @return  checksum
  7.      * @throws NoSuchAlgorithmException the no such algorithm exception
  8.      * @throws IOException              the io exception
  9.      */
  10.     public static String extractChecksum(String path, String algorithm) throws NoSuchAlgorithmException, IOException {
  11.         // 根据算法名称初始化摘要算法
  12.         MessageDigest digest = MessageDigest.getInstance(algorithm);
  13.         // 读取文件的所有比特
  14.         byte[] fileBytes = Files.readAllBytes(Paths.get(path));
  15.         // 摘要更新
  16.         digest.update(fileBytes);
  17.         //完成哈希摘要计算并返回特征值
  18.         byte[] digested = digest.digest();
  19.         // 进行十六进制的输出
  20.         return HexUtils.toHexString(digested);
  21.     }

接下来做几组对照试验来证明猜想。

内容不变

首先要证明一个文件在内容不变的情况下摘要是否有变化,多次执行下面的代码,断言始终都是true


   
  1. String path = "C:\\Users\\s1\\IdeaProjects\\demo\\src\\main\\resources\\application.yml";
  2.         String checksum = extractChecksum(path, "SHA-1");
  3.         String hash = "6bf4d6c101b4a7821226d3ec1f8d778a531bf265";
  4.         Assertions.assertEquals(hash,checksum);

而且我把文件名改成application-dev.yml,甚至application-dev.txt摘要都是相同的。我又把yml文件的内容作了改动,断言就false了。这证明了单个文件的情况下,内容不变,hash是不变的

文件复制

我把yml文件复制了一份,改了文件名称和类型,不改变内容并存到了另一个目录中,来测试一下它们的摘要是否有变化。


   
  1. String path1 = "C:\\Users\\s1\\IdeaProjects\\demo\\src\\main\\resources\\application.yml";
  2.         String path2 = "C:\\Users\\s1\\IdeaProjects\\demo\\src\\main\\resources\\templates\\application-dev.txt";
  3.         String checksum1 = extractChecksum(path1, "SHA-1");
  4.         String checksum2 = extractChecksum(path2, "SHA-1");
  5.         String hash = "6bf4d6c101b4a7821226d3ec1f8d778a531bf265";
  6.         Assertions.assertEquals(hash,checksum1);
  7.         Assertions.assertEquals(hash,checksum2);

结果断言通过,不过改变了其中一个文件的内容后断言就不通过了。

新建空文件

这里的新建空文件指的是没有进行任何操作的新建的空文件。

新建的空文件会根据特定的算法返回一个固定值,比如SHA-1算法下的空文件值是:

da39a3ee5e6b4b0d3255bfef95601890afd80709
  

结论

通过实验证明了:

  • 在相同算法下,任何新建空文件的摘要值都是固定的。

  • 任何两个内容相同的文件的摘要值都是相同的,和路径、文件名、文件类型无关。

  • 文件的摘要值会随着文件内容的改变而改变。

文件摘要运用

根据上面的结论,文件摘要是可以防止同样内容的文件重复提交的, 存储的时候不但要存储文件的路径,还要存储文件的摘要值,可能需要注意新建空文件的的固定摘要问题。另外在Java12中提供了新的API来处理文件内容重复问题,有兴趣的可以研究一下。文件摘要除了防篡改和去重之外,你知道还有其它什么用途吗?欢迎同学们留言讨论。

网易宣布:免费培养30名前端开发者,小白也有机会!

2021-11-30

53841c49a0f22196f9d865c7ae30edb2.png

Jetbrains正在开发下一代编辑器,对标VS Code,本文可申请体验

2021-11-29

bbb8c49bbc854824bab8783f49922c87.png

Spring Security动态权限越来越容易了

2021-11-22

a1d3793f376f2c109700d6226b360b90.png

23f6ecba5f1543ee6f3277dd27e6f965.gif

文章来源: felord.blog.csdn.net,作者:码农小胖哥,版权归原作者所有,如需转载,请联系作者。

原文链接:felord.blog.csdn.net/article/details/121668312

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。