iOS計算大文件的MD5

iOS計算MD5的方式有不少種:

1. 常見的方式

#include <CommonCrypto/CommonDigest.h>
/// 計算文件的MD5
- (NSString *)getFileMD5StrFromPath1:(NSString *)path {
	
	NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path];
	if( handle== nil ) return @""; // 若是文件不存在
	
	CC_MD5_CTX md5;
	
	CC_MD5_Init(&md5);
	
	BOOL done = NO;
	while(!done)
		{
		NSData* fileData = [handle readDataOfLength:256];
		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;
}
複製代碼

這種方式在計算文件較小的時候可以返回正確的值,
可是在遇到大文件(好比超過1G,具體的臨界值沒有肯定)會出現應用閃退現象。bash

第二種方式

/// 獲取文件的MD5值,若是文件不存在直接返回空字符串
- (NSString *)getFileMD5StrFromPath2:(NSString *)path {
	NSFileManager *fileManager = [NSFileManager defaultManager];
	
	if([fileManager fileExistsAtPath:path isDirectory:nil]) {
		
		NSData *data = [NSData dataWithContentsOfFile:path];
		
		unsigned char digest[CC_MD5_DIGEST_LENGTH];
		
		CC_MD5( data.bytes, (CC_LONG)data.length, digest );
		
		NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
		
		for( int i = 0; i < CC_MD5_DIGEST_LENGTH; i++ ) {
			[output appendFormat:@"%02x", digest[i]];
		}
		return output;
	} else {
		return @"";
	}
}
複製代碼

這種方式在計算文件較小的時候可以返回正確的MD5值,在計算大文件MD5值的時候,應用不會閃退可是會返回錯誤的MD5:"d41d8cd98f00b204e9800998ecf8427e",在MD5解密的網站進行解密的時候,返回結果是空字符串。app

查詢結果:
[空密碼]/[Empty String]
複製代碼

第三種方式,能夠計算大文件件的MD5

//首先聲明一個宏定義
#define FileHashDefaultChunkSizeForReadingData 1024*8
CFStringRef FileMD5HashCreateWithPath(CFStringRef filePath,
                                       size_t chunkSizeForReadingData) {
    
    // Declare needed variables
    CFStringRef result = NULL;
    CFReadStreamRef readStream = NULL;
    
    // Get the file URL
    CFURLRef fileURL =
    CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
                                  (CFStringRef)filePath,
                                  kCFURLPOSIXPathStyle,
                                  (Boolean)false);
    if (!fileURL) goto done;
    
    // Create and open the read stream
    readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault,
                                            (CFURLRef)fileURL);
    if (!readStream) goto done;
    bool didSucceed = (bool)CFReadStreamOpen(readStream);
    if (!didSucceed) goto done;
    
    // Initialize the hash object
    CC_MD5_CTX hashObject;
    CC_MD5_Init(&hashObject);
    
    // Make sure chunkSizeForReadingData is valid
    if (!chunkSizeForReadingData) {
        chunkSizeForReadingData = FileHashDefaultChunkSizeForReadingData;
    }
    
    // Feed the data to the hash object
    bool hasMoreData = true;
    while (hasMoreData) {
        uint8_t buffer[chunkSizeForReadingData];
        CFIndex readBytesCount = CFReadStreamRead(readStream,
                                                  (UInt8 *)buffer,
                                                  (CFIndex)sizeof(buffer));
        if (readBytesCount == -1) break;
        if (readBytesCount == 0) {
            hasMoreData = false;
            continue;
        }
        CC_MD5_Update(&hashObject,(const void *)buffer,(CC_LONG)readBytesCount);
    }
    
    // Check if the read operation succeeded
    didSucceed = !hasMoreData;
    
    // Compute the hash digest
    unsigned char digest[CC_MD5_DIGEST_LENGTH];
    CC_MD5_Final(digest, &hashObject);
    
    // Abort if the read operation failed
    if (!didSucceed) goto done;
    
    // Compute the string result
    char hash[2 * sizeof(digest) + 1];
    for (size_t i = 0; i < sizeof(digest); ++i) {
        snprintf(hash + (2 * i), 3, "%02x", (int)(digest[i]));
    }
    result = CFStringCreateWithCString(kCFAllocatorDefault,
                                       (const char *)hash,
                                       kCFStringEncodingUTF8);
    
done:
    
    if (readStream) {
        CFReadStreamClose(readStream);
        CFRelease(readStream);
    }
    if (fileURL) {
        CFRelease(fileURL);
    }
    return result;
}
/// 第二種方式計算大文件MD5
- (NSString*)getBigfileMD5:(NSString*)path
{
    return (__bridge_transfer NSString *)FileMD5HashCreateWithPath((__bridge CFStringRef)path, FileHashDefaultChunkSizeForReadingData);
}
複製代碼

這種方式是最爲嚴瑾的計算方法,能夠計算小文件,計算大文件時耗時較長可以計算正確的MD5值,網站

總結:ui

  1. 第一種方式是直接返回值沒有耗時操做可是可能會出現錯誤,、
  2. 第二種在計算大文件會閃退
  3. 可以完美計算全部文件的MD5,計算大文件會耗時(正常現象)
相關文章
相關標籤/搜索