超大文件如何计算md5?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了超大文件如何计算md5?相关的知识,希望对你有一定的参考价值。
首先,至少没必要先把整个文件读到内存里。比如在 php 里,如果有人 md5(file_get_contents(big_file_name)) 就确实非常不妥当。因为 md5 是每 512 bit 作为一个 chunk 进行计算的。所以可以每次读取一部分的内容(最少 512 bit,比较合适是 st_blksize),进行那些 chunk 部分的计算,之后再读取下一部分内容继续计算。简单先说下,md5是有规范的,提供了现成的算法(规范的名字就是md5算法。RFC 1321 The MD5 Message-Digest Algorithm),我们只需要翻译成c、java、python、js等等代码。前端算超大文件可以取头跟尾chunk内容及整个文件的name + update 时间一起算md5值就比较快了,只是为了做唯一标识来做断点续传,从业务逻辑上应该够用了。推荐使用 js spark-md5 开源库,支持直接append各个部分然后算出md5。我做的断点续传功能就是用它在前端算的md5. 各大网盘 TB级别 md5算法应该是这样的,楼上几位都说了文件md5是文件流分块算出来的,那么网盘想获得TB级别文件的md5就必须读取整个文件的文件流才能得到,但是这么做效率十分低下,运算时间是个问题。但是大家忽略了一个问题,文件在上传的过程也是分块上传的,这些上传的碎片其实也是文件流。那么可以把计算md5的时间分摊到每一个碎片上。这样每上传一个片段就计算一点等上传完成了,文件的md5也就算出来了。okTB级别MD5不是问题了。上传完成md5自然就出来了。 不知道我的猜测大家有其他看法没有。刚才提出都传完了就还怎么秒传。秒传最基本的是先要前端算出md5然后传给后端(可能需要更多种哈希值)我研究了很久前端没有办法秒内完成超大文件MD5的,现在用html5 的api 可以算出任意大小文件的 md5 但是耗时相当长。我没有解决办法。也没有想到那些网盘怎么在前端快速获取md5的。
参考技术A在最近的开发及原有方案的改良中,一个feture就是加快对GB级大文件的读取和计算MD5的速度。这是一个IO密集和CPU密集的耗时操作,在无法硬性提高CPU的条件下,我考虑从IO上如何提高速率。超大文件的MD5计算,需要分段将文件中的内存更新到MessageDigest中。(注:MessageDigest的实例不能共享,CSDN等博客上介绍MD5计算的demo,将MessageDigest设置为单例模式,单线程计算一个文件的MD5不会出错,多线程计算就会出问题了。)Java的NIO中提供了内存映射,通过将文件的一部分映射到内存中,可以一定程度地提高IO速率,从提高整体的效率。使用NIO的内存映射需要注意 内存的释放(之前未释放内存,在100GB级的文件测试中,抛出了OOM错误)。
参考技术BMd5是一种散列算法,理论上是不可解密的,而且重复的几率极小极小,因此在平常的密码存储上应用比较广泛,这个值一般情况下是唯一的,所以在文件校验上也应用的比较多,下面说明一下C#中字符串以及文件获取Md5值方法。网上所说的Md5解密并不是真正的解密,因为Md5本就是一种不可解密的算法,其所称解密只是把一些常用的字符串获取Md5值,然后存入数据库,若是你输入Md5值在数据库里存在,那么就会返回与之对应的字符串了,若是没有就自然无法获取了,所以说密码还是要起的复杂些,加入一些特殊字符更好些。
iOS 超大文件MD5加密,超大文件hmac加密
1、在文件超过1G的时候,不能一次性放入内存之中,但是我们还是需要将这个文件进行md5加密,或者hmac系列的加密
这个时候我们需要用到一个系统的api——update系列的方法
注意:参数path为大文件所在的路径。
//MARK:大文件的MD5加密 +(NSString*)fileMD5:(NSString*)path NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path]; if( handle== nil ) return @"ERROR GETTING FILE MD5"; // file didnt exist CC_MD5_CTX md5; CC_MD5_Init(&md5); BOOL done = NO; while(!done) NSData* fileData = [handle readDataOfLength:256]; // CHUNK_SIZE CC_MD5_Update(&md5, [fileData bytes], [fileData length]); if( [fileData length] == 0 ) done = YES; unsigned char digest[CC_MD5_DIGEST_LENGTH]; CC_MD5_Final(digest, &md5); NSString* s = [NSString stringWithFormat: @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]]; return s;
//MARK:大文件的hmacSHA256加密 + (NSString *)hmac:(NSString *)path withKey:(NSString *)key NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path]; if( handle== nil ) return @"ERROR GETTING FILE hmac"; // file didnt exist CCHmacContext ctx; const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH]; CCHmacInit(&ctx, kCCHmacAlgSHA256, cKey, strlen(cKey)); BOOL done = NO; while(!done) NSData* fileData = [handle readDataOfLength:256]; CCHmacUpdate(&ctx, [fileData bytes], [fileData length]); if( [fileData length] == 0 ) done = YES; CCHmacFinal(&ctx, cHMAC); NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)]; const unsigned char *buffer = (const unsigned char *)[HMACData bytes]; NSMutableString *HMAC = [NSMutableString stringWithCapacity:HMACData.length * 2]; for (int i = 0; i < HMACData.length; ++i) [HMAC appendFormat:@"%02x", buffer[i]]; return HMAC;
以上是关于超大文件如何计算md5?的主要内容,如果未能解决你的问题,请参考以下文章