Java 自带MD5 校验文件

http://www.iteye.com/topic/1127319

 

前天第一次发表博客到论坛,关于Java文件监控一文,帖子地址在:http://www.iteye.com/topic/1127281

评论的朋友很多,下载代码的朋友很不少,感谢在论坛上看我帖子的朋友,还有回复评论的朋友,给我提供建议的朋友。

 

从这些建议中,虽然语言简短,但是却有的是一语中的,这里说一下一下关于帖子的代码中HashFile中的MD5文件校验算法,

该算法是使用Java自带的MessageDigest类,测试结果,获取一个2G文件的MD5码,耗时 971秒,这效率太给力了,可以用坑爹来形容,所以用MD5文件校验码来判断文件是否被修改,对于小文件来说可能还合适,要是对大文件来说,好吧,撞墙死了算了!

 

HashFile中的代码是这样子的:

import java.io.FileInputStream;
import java.io.InputStream;
import java.security.MessageDigest;

public class HashFile { 
 
    /**
     * @param args
     */ 
    public static char[] hexChar = { ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, 
            ‘8‘, ‘9‘, ‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘, ‘f‘ };
 
    public static String getHash(String fileName, String hashType) 
            throws Exception { 
        InputStream fis; 
        fis = new FileInputStream(fileName); 
        byte[] buffer = new byte[1024]; 
        MessageDigest md5 = MessageDigest.getInstance(hashType); 
        int numRead = 0; 
        while ((numRead = fis.read(buffer)) > 0) { 
            md5.update(buffer, 0, numRead); 
        } 
        fis.close(); 
        return toHexString(md5.digest()); 
    } 
 
    public static String toHexString(byte[] b) { 
        StringBuilder sb = new StringBuilder(b.length * 2); 
        for (int i = 0; i < b.length; i++) { 
            sb.append(hexChar[(b[i] & 0xf0) >>> 4]); 
            sb.append(hexChar[b[i] & 0x0f]); 
        } 
        return sb.toString(); 
    } 

测试结果:

技术分享
真给力啊,超过2G,效率变成这样 !

好吧,自带的MD5算法,上当了,对于检查文件是否更新这个问题来说,现在我使用的解决办法是File 类的lastModified方法,代码这样

 通过比较文件的最后修改时间来判断文件是否更新,对大文件也轻松拿下,

测试结果是这样:


技术分享
 当然针对不同问题肯定是有不同的解决办法

 

分析原来HashFile代码,获取MD5校验码的瓶颈是出现在

Java代码 技术分享 技术分享
  1. public static String getHash(String fileName, String hashType)     
  2.             throws Exception {     
  3.         InputStream fis;     
  4.         fis = new FileInputStream(fileName);     
  5.         byte[] buffer = new byte[1024];     
  6.         MessageDigest md5 = MessageDigest.getInstance(hashType);     
  7.         int numRead = 0;     
  8.         while ((numRead = fis.read(buffer)) > 0) {  //瓶颈   
  9.             md5.update(buffer, 0, numRead);     
  10.         }     
  11.         fis.close();     
  12.         return toHexString(md5.digest());     
  13.     }    
public static String getHash(String fileName, String hashType)  
            throws Exception {  
        InputStream fis;  
        fis = new FileInputStream(fileName);  
        byte[] buffer = new byte[1024];  
        MessageDigest md5 = MessageDigest.getInstance(hashType);  
        int numRead = 0;  
        while ((numRead = fis.read(buffer)) > 0) {  //瓶颈
            md5.update(buffer, 0, numRead);  
        }  
        fis.close();  
        return toHexString(md5.digest());  
    }  

 在上面代码中,while循环N次,2G的文件,循环1024 * 1024  * 2 次,不给力!

 

chimer回复

来个nio的简单版,看你们老是怀疑java慢

C++ MD5工具验证结果:

File: K:\Games\World of Warcraft\Data\common.MPQ
Size: 2226587191 bytes
Modified: 2008年11月19日 星期三, 12:57:24
MD5: CD9F9C5523F3BA3866B81CCC74ED6476


java运行结果,毫秒
耗时:12672,cd9f9c5523f3ba3866b81ccc74ed6476


核心代码

String hashType = "MD5";
  FileInputStream fStream = null;
  try {
   MessageDigest md5 = MessageDigest.getInstance(hashType);
   fStream = new FileInputStream(
     //"K:\\Games\\World of Warcraft\\Scan.dll");
     //"K:\\Games\\World of Warcraft\\Data\\patch-3.MPQ");
     "K:\\Games\\World of Warcraft\\Data\\common.MPQ");
   FileChannel fChannel = fStream.getChannel();
   ByteBuffer buffer = ByteBuffer.allocate(8*1024);
   long s = System.currentTimeMillis();
   for ( int count = fChannel.read( buffer ); count !=-1 ; count = fChannel.read( buffer )
    ) {
    buffer.flip();
    md5.update( buffer );
    if( !buffer.hasRemaining() ){
     //System.out.println("count:"+count);
     buffer.clear();
    }
   }
   s = System.currentTimeMillis() - s;
   System.out.println( "耗时:"+s+","+getString( md5.digest() ) );
   
  } catch (NoSuchAlgorithmException e) {
   e.printStackTrace();
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }finally{
   try {
    if( fStream!=null )
     fStream.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。