【转】Java计算文件的hash值

原文地址:http://blog.csdn.net/qq_25646191/article/details/78863110

如何知道一个文件是否改变了呢?当然是用比较文件hash值的方法,文件hash又叫文件签名,文件中哪怕一个bit位被改变了,文件hash就会不同。

比较常用的文件hash算法有MD5和SHA-1。
我用的是MD5算法,java中,计算MD5可以用MessageDigest这个类。

下面是代码:

 

[java] view plain copy
  1. package com.test;    
  2.     
  3. import java.io.FileInputStream;    
  4. import java.io.FileNotFoundException;    
  5. import java.io.InputStream;    
  6. import java.math.BigInteger;    
  7. import java.security.MessageDigest;    
  8.     
  9. public class MD5Util {    
  10.         
  11.     public static void main(String[] args) {    
  12.         try {    
  13.             //此处我测试的是我本机jdk源码文件的MD5值   
  14.             String filePath = "C:\\Program Files\\Java\\jdk1.7.0_45\\src.zip";  
  15.               
  16.             String md5Hashcode = md5HashCode(filePath);  
  17.             String md5Hashcode32 = md5HashCode32(filePath);    
  18.               
  19.             System.out.println(md5Hashcode + ":文件的md5值");    
  20.             System.out.println(md5Hashcode32+":文件32位的md5值");   
  21.               
  22.             //System.out.println(-100 & 0xff);  
  23.         } catch (FileNotFoundException e) {    
  24.             e.printStackTrace();    
  25.         }    
  26.     }    
  27.       
  28.     /** 
  29.      * 获取文件的md5值 ,有可能不是32位 
  30.      * @param filePath  文件路径 
  31.      * @return 
  32.      * @throws FileNotFoundException 
  33.      */  
  34.     public static String md5HashCode(String filePath) throws FileNotFoundException{    
  35.         FileInputStream fis = new FileInputStream(filePath);    
  36.         return md5HashCode(fis);    
  37.     }    
  38.       
  39.     /** 
  40.      * 保证文件的MD5值为32位 
  41.      * @param filePath  文件路径 
  42.      * @return 
  43.      * @throws FileNotFoundException 
  44.      */  
  45.     public static String md5HashCode32(String filePath) throws FileNotFoundException{    
  46.         FileInputStream fis = new FileInputStream(filePath);    
  47.         return md5HashCode32(fis);    
  48.     }    
  49.       
  50.     /** 
  51.      * java获取文件的md5值   
  52.      * @param fis 输入流 
  53.      * @return 
  54.      */  
  55.     public static String md5HashCode(InputStream fis) {    
  56.         try {    
  57.             //拿到一个MD5转换器,如果想使用SHA-1或SHA-256,则传入SHA-1,SHA-256    
  58.             MessageDigest md = MessageDigest.getInstance("MD5");   
  59.               
  60.             //分多次将一个文件读入,对于大型文件而言,比较推荐这种方式,占用内存比较少。  
  61.             byte[] buffer = new byte[1024];    
  62.             int length = -1;    
  63.             while ((length = fis.read(buffer, 0, 1024)) != -1) {    
  64.                 md.update(buffer, 0, length);    
  65.             }    
  66.             fis.close();  
  67.             //转换并返回包含16个元素字节数组,返回数值范围为-128到127  
  68.             byte[] md5Bytes  = md.digest();  
  69.             BigInteger bigInt = new BigInteger(1, md5Bytes);//1代表绝对值   
  70.             return bigInt.toString(16);//转换为16进制  
  71.         } catch (Exception e) {    
  72.             e.printStackTrace();    
  73.             return "";    
  74.         }    
  75.     }    
  76.       
  77.     /** 
  78.      * java计算文件32位md5值 
  79.      * @param fis 输入流 
  80.      * @return 
  81.      */  
  82.     public static String md5HashCode32(InputStream fis) {  
  83.         try {  
  84.             //拿到一个MD5转换器,如果想使用SHA-1或SHA-256,则传入SHA-1,SHA-256    
  85.             MessageDigest md = MessageDigest.getInstance("MD5");  
  86.               
  87.             //分多次将一个文件读入,对于大型文件而言,比较推荐这种方式,占用内存比较少。  
  88.             byte[] buffer = new byte[1024];  
  89.             int length = -1;  
  90.             while ((length = fis.read(buffer, 0, 1024)) != -1) {  
  91.                 md.update(buffer, 0, length);  
  92.             }  
  93.             fis.close();  
  94.               
  95.             //转换并返回包含16个元素字节数组,返回数值范围为-128到127  
  96.             byte[] md5Bytes  = md.digest();  
  97.             StringBuffer hexValue = new StringBuffer();  
  98.             for (int i = 0; i < md5Bytes.length; i++) {  
  99.                 int val = ((int) md5Bytes[i]) & 0xff;//解释参见最下方  
  100.                 if (val < 16) {  
  101.                     /** 
  102.                      * 如果小于16,那么val值的16进制形式必然为一位, 
  103.                      * 因为十进制0,1...9,10,11,12,13,14,15 对应的 16进制为 0,1...9,a,b,c,d,e,f; 
  104.                      * 此处高位补0。 
  105.                      */  
  106.                     hexValue.append("0");  
  107.                 }  
  108.                 //这里借助了Integer类的方法实现16进制的转换   
  109.                 hexValue.append(Integer.toHexString(val));  
  110.             }  
  111.             return hexValue.toString();  
  112.         } catch (Exception e) {  
  113.             e.printStackTrace();  
  114.             return "";  
  115.         }  
  116.     }  
  117.       
  118.     /** 
  119.      * 方法md5HashCode32 中     ((int) md5Bytes[i]) & 0xff   操作的解释: 
  120.      * 在Java语言中涉及到字节byte数组数据的一些操作时,经常看到 byte[i] & 0xff这样的操作,这里就记录总结一下这里包含的意义:  
  121.      * 1、0xff是16进制(十进制是255),它默认为整形,二进制位为32位,最低八位是“1111 1111”,其余24位都是0。  
  122.      * 2、&运算: 如果2个bit都是1,则得1,否则得0;  
  123.      * 3、byte[i] & 0xff:首先,这个操作一般都是在将byte数据转成int或者其他整形数据的过程中;使用了这个操作,最终的整形数据只有低8位有数据,其他位数都为0。  
  124.      * 4、这个操作得出的整形数据都是大于等于0并且小于等于255的 
  125.      */  
  126.     
  127. }    

 

运行结果如下图:

PS:其实还有一个重点,就是如何知道自己生成的MD5值是否正确呢?

方法很多,其实有一个挺简单的方法,不需要另外安装什么软件。

使用windows自带的命令即可:certutil -hashfile [文件路径] MD5,

例子如下:

 

posted @ 2018-01-25 12:09  dirgo  阅读(10775)  评论(0编辑  收藏  举报