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

发表于:2021-12-06 09:49  作者:码农小胖哥   来源:码农小胖哥

字体: | 上一篇 | 下一篇 |我要投稿 | 推荐标签: 软件开发 Java

  今天做文件上传功能,需求要求文件内容相同的不能重复上传。感觉这个需求挺简单的就交给了一位刚入行的新同学。等合并代码的时候发现这位同学居然用文件名称相同和文件大小相同作为两个文件相同的依据。这种条件判断靠谱吗?
  从概率上来说遇到两个文件名称和大小都一样的概率确实太小了。这种判断放在生产环境中也可以稳定的跑上一阵子,不过即使再低的可能性也是有可能的,如果能做到100%就好了。
  文件摘要校验
  我相信同学们都下载过一些好心人开发的小工具,有些小工具会附带一个校验器让你校验附带提供的checksum值,防止有人恶意篡改小工具,保证小工具可以放心使用。
文件Hash校验

  如果两个文件的内容相同,那么它们的摘要应该是相同的。这个原理能不能帮助我们鉴定两个文件是否相同呢?
  Java实现文件摘要
  带着这个疑问,我写了一个文件摘要提取工具类:
  /** 
   * 提取文件 checksum  
   * 
   * @param path      文件全路径 
   * @param algorithm  算法名 例如 MD5、SHA-1、SHA-256等 
   * @return  checksum 
   * @throws NoSuchAlgorithmException the no such algorithm exception 
   * @throws IOException              the io exception 
   */ 
  public static String extractChecksum(String path, String algorithm) throws NoSuchAlgorithmException, IOException { 
      // 根据算法名称初始化摘要算法 
      MessageDigest digest = MessageDigest.getInstance(algorithm); 
      // 读取文件的所有比特 
      byte[] fileBytes = Files.readAllBytes(Paths.get(path)); 
      // 摘要更新 
      digest.update(fileBytes); 
      //完成哈希摘要计算并返回特征值 
      byte[] digested = digest.digest(); 
      // 进行十六进制的输出 
      return HexUtils.toHexString(digested); 
  } 
  接下来做几组对照试验来证明猜想。
  内容不变
  首先要证明一个文件在内容不变的情况下摘要是否有变化,多次执行下面的代码,断言始终都是true。
  String path = "C:\\Users\\s1\\IdeaProjects\\demo\\src\\main\\resources\\application.yml"; 
   
  String checksum = extractChecksum(path, "SHA-1"); 
   
  String hash = "6bf4d6c101b4a7821226d3ec1f8d778a531bf265"; 
   
  Assertions.assertEquals(hash,checksum); 
  而且我把文件名改成application-dev.yml,甚至application-dev.txt摘要都是相同的。我又把yml文件的内容作了改动,断言就false了。这证明了单个文件的情况下,内容不变,hash是不变的。
  文件复制
  我把yml文件复制了一份,改了文件名称和类型,不改变内容并存到了另一个目录中,来测试一下它们的摘要是否有变化。
  String path1 = "C:\\Users\\s1\\IdeaProjects\\demo\\src\\main\\resources\\application.yml"; 
   
  String path2 = "C:\\Users\\s1\\IdeaProjects\\demo\\src\\main\\resources\\templates\\application-dev.txt"; 
   
  String checksum1 = extractChecksum(path1, "SHA-1"); 
   
  String checksum2 = extractChecksum(path2, "SHA-1"); 
   
  String hash = "6bf4d6c101b4a7821226d3ec1f8d778a531bf265"; 
   
  Assertions.assertEquals(hash,checksum1); 
   
  Assertions.assertEquals(hash,checksum2); 
  结果断言通过,不过改变了其中一个文件的内容后断言就不通过了。
  新建空文件
  这里的新建空文件指的是没有进行任何操作的新建的空文件。
  新建的空文件会根据特定的算法返回一个固定值,比如SHA-1算法下的空文件值是:
  da39a3ee5e6b4b0d3255bfef95601890afd80709 
  结论
  通过实验证明了:
  在相同算法下,任何新建空文件的摘要值都是固定的。
  任何两个内容相同的文件的摘要值都是相同的,和路径、文件名、文件类型无关。
  文件的摘要值会随着文件内容的改变而改变。

  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理

评 论

论坛新帖



建议使用IE 6.0以上浏览器,800×600以上分辨率,法律顾问:上海信义律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2021, 沪ICP备05003035号
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪公网安备 31010102002173号

51Testing官方微信

51Testing官方微博

扫一扫 测试知识全知道