判断文件的唯一性--MD5
JAVA中获取文件MD5值的四种方法其实都很类似,因为核心都是通过JAVA自带的MessageDigest类来实现。获取文件MD5值主要分为三个步骤,第一步获取文件的byte信息,第二步通过MessageDigest类进行MD5加密,第三步转换成16进制的MD5码值。几种方法的不同点主要在第一步和第三步上。具体可以看下面的例子:
方法一、

 1   private final static String[] strHex = { "0", "1", "2", "3", "4", "5",
 2             "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
 3
 4     public static String getMD5One(String path) {
 5         StringBuffer sb = new StringBuffer();
 6         try {
 7             MessageDigest md = MessageDigest.getInstance("MD5");
 8             byte[] b = md.digest(FileUtils.readFileToByteArray(new File(path)));
 9             for (int i = 0; i < b.length; i++) {
10                 int d = b[i];
11                 if (d < 0) {
12                     d += 256;
13                 }
14                 int d1 = d / 16;
15                 int d2 = d % 16;
16                 sb.append(strHex[d1] + strHex[d2]);
17             }
18         } catch (NoSuchAlgorithmException e) {
19             e.printStackTrace();
20         } catch (IOException e) {
21             e.printStackTrace();
22         }
23         return sb.toString();
24     }

方法一是比较原始的一种实现方法,首先将文件一次性读入内存,然后通过MessageDigest进行MD5加密,最后再手动将其转换为16进制的MD5值。
方法二、

 1   public static String getMD5Two(String path) {
 2         StringBuffer sb = new StringBuffer("");
 3         try {
 4             MessageDigest md = MessageDigest.getInstance("MD5");
 5             md.update(FileUtils.readFileToByteArray(new File(path)));
 6             byte b[] = md.digest();
 7             int d;
 8             for (int i = 0; i < b.length; i++) {
 9                 d = b[i];
10                 if (d < 0) {
11                     d = b[i] & 0xff;
12                     // 与上一行效果等同
13                     // i += 256;
14                 }
15                 if (d < 16)
16                     sb.append("0");
17                 sb.append(Integer.toHexString(d));
18             }
19         } catch (NoSuchAlgorithmException e) {
20             e.printStackTrace();
21         } catch (IOException e) {
22             e.printStackTrace();
23         }
24         return sb.toString();
25     }

方法二与方法一不同的地方主要是在步骤三,这里借助了Integer类的方法实现16进制的转换,比方法一更简洁一些。PS:JAVA中byte是有负数的,代码中&0xff的操作与计算机中数据存储的原理有关,即负数存储的是二进制的补码,有兴趣的童鞋可以挖一下,这里不展开说。
方法三、

 1   public static String getMD5Three(String path) {
 2         BigInteger bi = null;
 3         try {
 4             byte[] buffer = new byte[8192];
 5             int len = 0;
 6             MessageDigest md = MessageDigest.getInstance("MD5");
 7             File f = new File(path);
 8             FileInputStream fis = new FileInputStream(f);
 9             while ((len = fis.read(buffer)) != -1) {
10                 md.update(buffer, 0, len);
11             }
12             fis.close();
13             byte[] b = md.digest();
14             bi = new BigInteger(1, b);
15         } catch (NoSuchAlgorithmException e) {
16             e.printStackTrace();
17         } catch (IOException e) {
18             e.printStackTrace();
19         }
20         return bi.toString(16);
21     }

方法三与前面两个方法相比,在读入文件信息上有点不同。这里是分多次将一个文件读入,对于大型文件而言,比较推荐这种方式,占用内存比较少。步骤三则是通过BigInteger类提供的方法进行16进制的转换,与方法二类似。
方法四、
1 DigestUtils.md5Hex(new FileInputStream(path));
方法四应该是最便捷的吧,哈哈,好东西要留在最后,如果你只需要使用标准的MD5,其实一行代码就够了,JAVA自带的commons-codec包就提供了获取16进制MD5值的方法。其底层实现上,也是分多次将一个文件读入,类似方法三。所以性能上也不错。
总结:其实方法都是类似的,推荐使用方法四,简洁且性能不错,当然,如果要做一些调整什么的,可以根据自己的需求进行方法的选择。
PS:其实还有一个重点,就是如何知道自己生成的MD5值是否正确呢?
方法很多,其实有一个挺简单的方法,不需要另外安装什么软件。使用windows自带的命令即可:certutil -hashfile [文件路径] MD5,例子如下:

最后给MD5的Java实现:
public class MD5{    /*    *四个链接变量    */    private final int A=0x67452301;    private final int B=0xefcdab89;    private final int C=0x98badcfe;    private final int D=0x10325476;    /*    *ABCD的临时变量    */    private int Atemp,Btemp,Ctemp,Dtemp;         /*    *常量ti    *公式:floor(abs(sin(i+1))×(2pow32)    */    private final int K[]={        0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,        0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8,        0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,        0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51,        0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,        0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,        0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681,        0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60,        0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,        0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244,        0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92,        0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314,        0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391};    /*    *向左位移数,计算方法未知    */    private final int s[]={7,12,17,22,7,12,17,22,7,12,17,22,7,        12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,        4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10,        15,21,6,10,15,21,6,10,15,21,6,10,15,21};              /*    *初始化函数    */    private void init(){        Atemp=A;        Btemp=B;        Ctemp=C;        Dtemp=D;    }    /*    *移动一定位数    */    private    int    shift(int a,int s){        return(a<<s)|(a>>>(32-s));//右移的时候,高位一定要补零,而不是补充符号位    }    /*    *主循环    */    private void MainLoop(int M[]){        int F,g;        int a=Atemp;        int b=Btemp;        int c=Ctemp;        int d=Dtemp;        for(int i = 0; i < 64; i ++){            if(i<16){                F=(b&c)|((~b)&d);                g=i;            }else if(i<32){                F=(d&b)|((~d)&c);                g=(5*i+1)%16;            }else if(i<48){                F=b^c^d;                g=(3*i+5)%16;            }else{                F=c^(b|(~d));                g=(7*i)%16;            }            int tmp=d;            d=c;            c=b;            b=b+shift(a+F+K[i]+M[g],s[i]);            a=tmp;        }        Atemp=a+Atemp;        Btemp=b+Btemp;        Ctemp=c+Ctemp;        Dtemp=d+Dtemp;         }    /*    *填充函数    *处理后应满足bits≡448(mod512),字节就是bytes≡56(mode64)    *填充方式为先加一个0,其它位补零    *最后加上64位的原来长度    */    private int[] add(String str){        int num=((str.length()+8)/64)+1;//以512位,64个字节为一组        int strByte[]=new int[num*16];//64/4=16,所以有16个整数        for(int i=0;i<num*16;i++){//全部初始化0            strByte[i]=0;        }        int    i;        for(i=0;i<str.length();i++){            strByte[i>>2]|=str.charAt(i)<<((i%4)*8);//一个整数存储四个字节,小端序        }        strByte[i>>2]|=0x80<<((i%4)*8);//尾部添加1        /*        *添加原长度,长度指位的长度,所以要乘8,然后是小端序,所以放在倒数第二个,这里长度只用了32位        */        strByte[num*16-2]=str.length()*8;            return strByte;    }    /*    *调用函数    */    public String getMD5(String source){        init();        int strByte[]=add(source);        for(int i=0;i<strByte.length/16;i++){        int num[]=new int[16];        for(int j=0;j<16;j++){            num[j]=strByte[i*16+j];        }        MainLoop(num);        }        return changeHex(Atemp)+changeHex(Btemp)+changeHex(Ctemp)+changeHex(Dtemp);         }    /*    *整数变成16进制字符串    */    private String changeHex(int a){        String str="";        for(int i=0;i<4;i++){            str+=String.format("%2s", Integer.toHexString(((a>>i*8)%(1<<8))&0xff)).replace(' ', '0');        }        return str;    }    /*    *单例    */    private static MD5 instance;    public static MD5 getInstance(){        if(instance==null){            instance=new MD5();        }        return instance;    }         private MD5(){};         public static void main(String[] args){        String str=MD5.getInstance().getMD5("");        System.out.println(str);    }}判断文件的唯一性--MD5的更多相关文章
- Linux下校验下载文件的完整性(MD5,SHA1,PGP)
		查看: Linux下校验下载文件的完整性(MD5,SHA1,PGP) http://blog.useasp.net/archive/2014/03/29/use-md5-sha1-or-pgp-to- ... 
- renameTo()判断文件是否被占用(判断大文件是否完成拷贝这个动作)
		在开发需求中有一个需求是监控目录下拷贝进来的文件,并对文件进行处理, 使用的java.nio . watchService 进行的处理,如果小文件还好一点,拷贝就是一瞬间的事情,但是如果是一个大文件 ... 
- [sh]md5sum接变量,find排除,sh判断文件存在
		1.md5sum md5sum `cat path_to_file|dos2unix` 注: 发现有些linux是gbk编码, 导致md5或ls 接变量后报错.需要dos2unix处理 2.find排 ... 
- C语言中如何判断文件是否存在
		方法一:access函数判断文件夹或者文件是否存在 函数原型: int access(const char *filename, int mode); 所属头文件:io.h filename:可以填写 ... 
- JavaScript根据文件名判断文件类型
		//JavaScript根据文件名判断文件类型 var imgExt = new Array(".png",".jpg",".jpeg",& ... 
- PHP判断文件或者目录是否可写
		在PHP中,可用is_writable()函数来判断一个 文件/目录 是否可写,详情如下: 参考 is_writable (PHP 4, PHP 5) is_writable — 判断给定的文件名是否 ... 
- python os 命令,及判断文件夹是否存在
		使用前 import os导入模块 os模块: os.sep 可以取代操作系统特定的路径分割符 os.linesep 字符串给出当前平台使用的行终止符.例如,Windows使用'\r\n ... 
- C# 判断文件有没占用
		C# 判断文件有没占用 using System; using System.Collections.Generic; using System.Text; using System.Runtime. ... 
- Java 判断文件夹、文件是否存在、否则创建文件夹
		1.判断文件是否存在,不存在创建文件 File file=new File("C:\\Users\\QPING\\Desktop\\JavaScript\\2.htm"); if( ... 
随机推荐
- Windows10 bypassUAC绕过用户账户控制
			使用这个github上的项目: https://github.com/L3cr0f/DccwBypassUAC 可以自行编译 全程UAC不介入,没反应. 测试: 权限提升真实有效 
- postman之如何获取cookie
			1.最近在学习postman的使用方法,为了保证后续模块操作,必须在登录时获取的session值,并将其设置为环境变量,session的位置处于response headers里面返回的set-coo ... 
- ubuntu 安装 c语言的库函数man手册
			安装 1.C语言库函数基本的帮助文档 sudo apt-get install manpages sudo apt-get install manpages-de sudo apt-get insta ... 
- VS2008 快捷键大全
			转载自 https://www.cnblogs.com/likebeta/archive/2013/02/20/2919224.html Ctrl+E,D ---- 格式化全部 ... 
- JAVA基础部分复习(七、JAVA枚举类型使用)
			/** * java中的枚举 * 枚举(enum),是指一个经过排序的.被打包成一个单一实体的项列表.一个枚举的实例可以使用枚举项列表中任意单一项的值. * 枚举在各个语言当中都有着广泛的应用,通常用 ... 
- mysql数据库简单入门
			1.xampp 跨平台 优点:兼容性高 2. apache(服务器) 著名的集成环境(也叫集成安装包) 功能:一般在网站上运行,优点:稳定 缺点:性能上有瓶颈 nginx 优点:快 3. mysql ... 
- django 增加自定义权限的一个博客,讲的很详细
			来自 https://www.cnblogs.com/huangxm/p/5770735.html 
- hnsdfz -- 6.19 -- day4
			感觉还好…… 暴力分挂了很多不知道为什么…… 听说今天出题人hsh很劲…… c题正解是个奇怪的知识点…… 恩总的来说今天的节奏依旧很散(大课间去围观sdfz跑操了233 暴力分都写了但是似乎没有尝试脑 ... 
- 【java多线程】队列系统之ArrayBlockingQueue源码
			1.简介 ArrayBlockingQueue,顾名思义:基于数组的阻塞队列.数组是要指定长度的,所以使用ArrayBlockingQueue时必须指定长度,也就是它是一个有界队列. 它实现了Bloc ... 
- Delphi操作剪贴板
			Windows使用剪贴板观察器和观察链.剪贴板观察器是一个显示剪贴板当前内容的窗口. 通常它应该至少能显示三种普通格式的内容:文字CF_TEXT.位图CF_BITMAP.元文件C ... 
