专栏名称: 安卓开发精选
伯乐在线旗下账号,分享安卓应用相关内容,包括:安卓应用开发、设计和动态等。
目录
相关文章推荐
开发者全社区  ·  奇女子!钓男朋友翻车了 ·  15 小时前  
开发者全社区  ·  年薪300万大厂程序员被女友晒工资单被裁,百 ... ·  昨天  
开发者全社区  ·  英区金融妲己 ·  2 天前  
开发者全社区  ·  色魔博士抓捕现场 ·  2 天前  
51好读  ›  专栏  ›  安卓开发精选

Android大文件上传秒传之MD5篇(上)

安卓开发精选  · 公众号  · android  · 2016-11-23 22:50

正文

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


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

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

点击 → 了解如何加入专栏作者


前言


现在越来越多的应用开始有上传大文件的需求,以及秒传,续传功能。由于最近学习大文件分隔上传,以及秒传的实现,给予分享的这种精神,我想将自己的学习过程,以及遇到的问题做一个总结,希望对有这方面需求的小伙伴有一定的帮助。


源码传送门

  • https://github.com/xiehui999/fuseProgram


分析


说到大文件上传,我们可能首先会想的一些网盘App,这些优秀的网盘除了上传大文件外,还可以实现秒传以及断点续传功能。说起断点续传也就明白了文章题目所说的大文件分片,由于网络的原因,一个大文件例如一百兆的文件,很有可能中途上传到一半或者50MB,或者上传到99MB时候失败了,如果下次再上传时还从头开始上传,这个体验很少人能接受的,如果你要真做成这样的话,那么客户一定会严重流失,所以我们需要对其分片或者说下次上传时从失败的地方开始上传。相信使用网盘较多的朋友都知道有一个很6的功能就是秒传,可能你很难相信为何我几百兆甚至几个G的文件,为何几秒内就上传成功了,为何这么神奇,其实原理也很简单,就是我们每次上传文件时每一个文件都会有一个独一无二的特征值,当我们上传文件时,他首先会检测服务器是否有该特征值的文件,,如果有的话,就不需要占用网络带宽,直接复制一份到你的网盘。今天分享的这篇文章便是为秒传打下坚实基础的,获取大文件的特征值-MD5.


MD5消息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5由罗纳德·李维斯特设计,于1992年公开,用以替换MD4算法


MessageDigest


在java.security这个包下有一个类MessageDigest ,通过名字我们就知道是消息摘要的意思,那么本篇文章也是有MessageDigest 这个类展开讨论。


//方法1:返回MessageDigest实例 algorithm算法名称

public static MessageDigest getInstance ( String algorithm )

throws NoSuchAlgorithmException {}

//方法2:更新计算消息摘要的数据内容

public void update ( byte [] input ) {}

//方法3:计算消息摘要并重置

public byte [] digest (){}


对于计算文件的MD5,我们主要用的上面的几个方法。方法1主要是进行初始化操作,需要指定算法,方法2是进行消息摘要内容的更新。而方法3就是最重要的一步,计算消息摘要的值并返回。


读取文件


对于文件的读取有很多种方式,例如通过FileInputStream读取字节流,也可以包装成InputStreamReader读取字节流,也可以包装成BufferedInputStream进行带缓冲区的读取,以及RandomAccessFile或者nio 包中FileChannel加内存映射的方式。当然各种方式的性能不言而喻(对流不熟悉的自行补脑)。


具体实现


FileInputStream字节流方式


/**

* 获取文件的MD5值

*

* @param file 文件路径

* @return md5

*/

public static String getFileMd5 ( File file ) {

MessageDigest messageDigest ;

//MappedByteBuffer byteBuffer = null;

FileInputStream fis = null ;

try {

messageDigest = MessageDigest . getInstance ( "MD5" );

if ( file == null ) {

return "" ;

}

if ( ! file . exists ()) {

return "" ;

}

int len = 0 ;

fis = new FileInputStream ( file );

//普通流读取方式

byte [] buffer = new byte [ 1024 * 1024 * 10 ];

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

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

messageDigest . update ( buffer , 0 , len );

}

BigInteger bigInt = new BigInteger ( 1 , messageDigest . digest ());

String md5 = bigInt . toString ( 16 );

while ( md5 . length () 32 ) {

md5 = "0" + md5 ;

}

return md5 ;

} catch ( NoSuchAlgorithmException e ) {

// TODO Auto-generated catch block

e . printStackTrace ();

} catch ( FileNotFoundException e ) {

// TODO Auto-generated catch block

e . printStackTrace ();

} catch ( IOException e ) {

// TODO Auto-generated catch block

e . printStackTrace ();

} finally {

try {

if ( fis != null ) {

fis . close ();

fis = null ;

}

} catch ( IOException e ) {

// TODO Auto-generated catch block

e . printStackTrace ();

}

}

return "" ;

}


FileChannel +MappedByteBuffer 方式


/**

* FileChannel 获取文件的MD5值

*

* @param file 文件路径

* @return md5

*/

public static String getFileMd52 ( File file ) {

MessageDigest messageDigest ;

FileInputStream fis = null ;

FileChannel ch = null ;

try {

messageDigest = MessageDigest . getInstance ( "MD5" );

if ( file == null ) {

return "" ;

}

if ( ! file . exists ()) {

return "" ;

}

fis = new FileInputStream ( file );

ch = fis . getChannel ();

int size = 1024 * 1024 * 10 ;

long part = file . length () / size + ( file . length () % size > 0 ? 1 : 0 );

System . err . println ( "文件分片数" + part );

for ( int j = 0 ; j part ; j ++ ) {

MappedByteBuffer byteBuffer = ch . map ( FileChannel . MapMode . READ_ONLY , j * size , j == part - 1 ? file . length () : ( j + 1 ) * size );

messageDigest . update ( byteBuffer );

byteBuffer . clear ();

}

BigInteger bigInt = new BigInteger ( 1 , messageDigest . digest ());

String md5 = bigInt . toString ( 16 );

while ( md5 . length () 32 ) {

md5 = "0" + md5 ;

}

return md5 ;

} catch ( NoSuchAlgorithmException e ) {

// TODO Auto-generated catch block

e . printStackTrace ();

} catch ( FileNotFoundException e ) {

// TODO Auto-generated catch block

e . printStackTrace ();

} catch ( IOException e ) {

// TODO Auto-generated catch block

e . printStackTrace ();

} finally {

try {

if ( fis != null ) {

fis . close ();

fis = null ;

}

if ( ch != null ){

ch . close ();

ch = null ;

}

} catch ( IOException e ) {

// TODO Auto-generated catch block

e . printStackTrace ();

}

}

return "" ;

}


/**

* FileChannel 获取文件的MD5值

*

* @param file 文件路径

* @return md5

*/

public static String getFileMd52 ( File file ) {

MessageDigest messageDigest ;

FileInputStream fis = null ;

FileChannel ch = null ;

try {

messageDigest = MessageDigest . getInstance ( "MD5" );

if ( file == null ) {

return "" ;

}

if ( ! file . exists ()) {

return "" ;

}

fis = new FileInputStream ( file );

ch = fis . getChannel ();

int size = 1024 * 1024 * 10 ;

long part = file . length () / size + ( file . length







请到「今天看啥」查看全文