一般我們在使用http或者socket上傳或者下載文件的時候,經常會在完成之后經行一次md5值得校驗(尤其是在斷點續傳的時候用的更
多),校驗MD5值是為了防止在傳輸的過程當中丟包或者數據包被篡改,在使用MD5之前呢我們應該先了解MD5的一些常識。MD5 百度百科
簡單的來說:
1)、MD5是使用哈希算法計算文件或字符串的摘要,對MD5算法簡要的敘述可以為:MD5以512位分組來處理輸入的信息,且每一分組又被劃分為16個32位子分組,經過了一系列的處理后,算法的輸出由四個32位分組組成,將這四個32位分組級聯后將生成一個128位散列值。128/ 8 = 16,也就是說MD5得到的是一組16字節長度的八進制。
2)、一般在使用的時候需要將它轉換成十六進制輸出,并且同時輸出為小寫。
在有了這些基礎知識之后,計算MD5就沒有那么大的難度了,最近在做大文件MD5計算的時候在網上搜到了一大堆ios MD5的代碼,其中有一大部分都不能用,尤其是 使用
NSFileHandle* handle = [NSFileHandle fileHandleForReadingAtPath:_filePath]; 這種方法的,就最坑了,應為它永遠讀取的是文件的固定的位置,而并不是計算整個文件的MD5摘要,所以永遠讓你陷入尷尬的境地。例如:(
NSData* fileData = [handle readDataOfLength: 1024*8]; //永遠讀取的是從開始位置開始,1024*8長度的文件, 如果使用這種方法的話,必須在每次讀取之前將文件讀取的位置設置為指定的位置,應該使用NSFileHandle的 - (void)seekToFileOffset:(unsigned long long)offset;
)
下面貼上我找的能用的一段代碼:親測各個平臺同一個計算出來的MD5值相同。(在使用的時候,可能會見
FileHashDefaultChunkSizeForReadingData 未定義的情況,那么你應該顯示的在頭文件里加入混定義:
#define FileHashDefaultChunkSizeForReadingData 1024*8
)
代碼如下:
+(NSString*)getFileMD5WithPath:(NSString*)path
{
return (__bridge_transfer NSString *)FileMD5HashCreateWithPath((__bridge CFStringRef)path, FileHashDefaultChunkSizeForReadingData);
}
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;
}
新聞熱點
疑難解答