android file md5,Android大文件上传秒传之MD5篇(下)

(点击上方公众号,可快速关注)

来源:伯乐在线专栏作者 - Code4Android

链接:http://android.jobbole.com/85154/

接上文

RandomAccessFile 方式

/**

* RandomAccessFile 获取文件的MD5值

*

* @param file 文件路径

* @return md5

*/

publicstaticStringgetFileMd53(Filefile){

MessageDigestmessageDigest;

RandomAccessFilerandomAccessFile=null;

try{

messageDigest=MessageDigest.getInstance("MD5");

if(file==null){

return"";

}

if(!file.exists()){

return"";

}

randomAccessFile=newRandomAccessFile(file,"r");

byte[]bytes=newbyte[1024*1024*10];

intlen=0;

while((len=randomAccessFile.read(bytes))!=-1){

messageDigest.update(bytes,0,len);

}

BigIntegerbigInt=newBigInteger(1,messageDigest.digest());

Stringmd5=bigInt.toString(16);

while(md5.length()<32){

md5="0"+md5;

}

returnmd5;

}catch(NoSuchAlgorithmExceptione){

// TODO Auto-generated catch block

e.printStackTrace();

}catch(FileNotFoundExceptione){

// TODO Auto-generated catch block

e.printStackTrace();

}catch(IOExceptione){

// TODO Auto-generated catch block

e.printStackTrace();

}finally{

try{

if(randomAccessFile!=null){

randomAccessFile.close();

randomAccessFile=null;

}

}catch(IOExceptione){

// TODO Auto-generated catch block

e.printStackTrace();

}

}

return"";

}

性能对比

我们选了一个小的文件,大概1M左右,观察执行时间

11-0911:49:20.21012678-12678/com.example.xhI/System.out:FileInputStream执行时间:179

11-0911:49:20.26612678-12678/com.example.xhI/System.out:FileChannel执行时间:55

11-0911:49:20.32212678-12678/com.example.xhI/System.out:RandomAccessFile执行时间:58

但是我选择大概10M的文件FileChannel+MappedByteBuffer性能并不明显,最后通过查询资料学习发现MappedByteBuffer这个东西很可怕,这个回收是不确定的,在手机上测试FileChannel效率并不是最好的。如果要计算一个几百兆的大文件,发现FileChannel+MappedByteBuffer还很容易OOM,原因就是MappedByteBuffer内存占用、文件关闭不确定,被其打开的文件只有在垃圾回收的才会被关闭,而且这个时间点是不确定的。当文件达到100M时就出现OOM如下

FATALEXCEPTION:main

java.lang.OutOfMemoryError

atjava.security.MessageDigestSpi.engineUpdate(MessageDigestSpi.java:85)

atjava.security.MessageDigest.update(MessageDigest.java:369)

所以在Android设备上尽量不要使用nio中的内存映射。在官方文档中有这样的一句话:A mapped byte buffer and the file mapping that it represents remain valid until the buffer itself is garbage-collected.

那么我们来计算一个大文件的MD5,此时我测试的文件是300多兆

11-0916:06:49.9303101-3101/com.example.xhI/System.out:FileInputStream执行时间:4219

11-0916:06:54.4903101-3101/com.example.xhI/System.out:RandomAccessFile执行时间:2162

通过日志发现RandomAccessFile的效率还是很明显的,此时使用FileChannel+MappedByteBuffer就OOM了,虽然使用了分段映射 也调用了MappedByteBuffer的clear()方法。当然通过日志你肯定明白计算文件MD5值是一个比较耗时的操作,不要再主线程中计算。

计算MD5

我们需要注意对于较大的文件计算MD5,我们不要一次将文件读取然后调用update方法。不然执行update方法时就会出现OOM。我们可以分段读取多次调用update方法,如下

while((len=fis.read(buffer))>0){

//该对象通过使用 update()方法处理数据

messageDigest.update(buffer,0,len);

}

你要明白调用执行update并没有计算MD5的值,真正计算的MD5值是调用digest(),该方法返回的是一个byte数组

byte[]bytes=messageDigest.digest();

通常我们一般将MD5用16进制也就是32位表示,所以我们可以将byte数组转化为16进制,此时我们可以使用BigInteger类,他的构造方法可以接收byte数组参数,如下,1表示符号为正数。

BigIntegerbigInt=newBigInteger(1,bytes);

BigInteger这个类还提供了一个toString方法该参数可以指定转化数据格式,由于我们转化为16进制,所以参数可以写16,如下

Stringmd5=bigInt.toString(16);

OK了,MD5的值已经出现了,不过你可能会疑问了,转化为16进制的话,MD5值应该是32位,为何有时候计算的值不是32位,而是31位呢?甚至还可能更少,原因就是digest()返回值的高位包含了0,当然高位0是不写的,所以就出现少位的情况,这也就有了下面的代码,如果不到32位我们再高位补0就好了。

while(md5.length()<32){

md5="0"+md5;

}

至此,本篇文章结束,若有不足的地方欢迎指正,谢谢。

Code4Android:简介还没来得及写 :)

0818b9ca8b590ca3270a3433284dd417.png

打赏支持作者写出更多好文章,谢谢!

关注「安卓开发精选」看更多精选文章↓↓↓

0818b9ca8b590ca3270a3433284dd417.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值