• 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方法,代码这样

    private String getHash(String fp){
      File file = new File(fp);
      return String.valueOf(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:GamesWorld of WarcraftDatacommon.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();
       }
      }

  • 相关阅读:
    使用Visual Studio .Net 做自己的汉化软件
    给所有的Control加两个属性,实现回车键自动跳转到下一个控件
    数字逗号标记—以前原创(一)
    解决w3wp.exe占用CPU和内存问题
    sql日期函数
    索引的使用总结
    w3wp.exe狂占内存
    w3wp.exe占内存CPU问题 WIN2003 IIS6.0假死现象的分析
    查看Linux系统日志
    linux动态增加LV空间
  • 原文地址:https://www.cnblogs.com/yangyudexiaobai/p/4452776.html
Copyright © 2020-2023  润新知