一、摘要 1.七牛上傳文件,用hash來唯一標識七牛存儲空間中的某個文件,該hash是以ETag演算法計算出的一段哈希值; 2.演算法介紹:https://developer.qiniu.com/kodo/manual/1231/appendix; 3.七牛的提供的實現語言中(https://githu ...
一、摘要
1.七牛上傳文件,用hash來唯一標識七牛存儲空間中的某個文件,該hash是以ETag演算法計算出的一段哈希值;
2.演算法介紹:https://developer.qiniu.com/kodo/manual/1231/appendix;
3.七牛的提供的實現語言中(https://github.com/qiniu/qetag),沒有給出OC實現;
4.參考js代碼:https://www.jianshu.com/p/3785fc314fc5;
二、代碼
- (void)test2 { /*測試鏈接 http://yqq.file.mediportal.com.cn/yqq_5b911b43955f06317c6bd792/3974e8eaab11b2dd5b357e60e5a587d1 etag:FtfVrVsdpVf9t_tCfyvsVC-1p6aW 4M以上文件親測正確 */ NSURL *url = [NSURL URLWithString:@"http://yqq.file.mediportal.com.cn/yqq_5b911b43955f06317c6bd792/3974e8eaab11b2dd5b357e60e5a587d1"]; NSError *error; NSData * data = [NSData dataWithContentsOfURL:url options:NSDataReadingMapped error:&error]; NSString *etag = [self caculateETagWith:data]; NSLog(@"etag------%@", etag); } //演算法實現 - (NSString *)caculateETagWith:(NSData *)data { unsigned long blockSize = 4 * 1024 * 1024; NSMutableData *sha1Data = [NSMutableData data]; Byte prefix = 0x16; int blockCount = 0; unsigned long bufferSize = [data length]; //獲取餘數 unsigned long remainder = bufferSize % blockSize; //獲取商 double fa = (double)bufferSize / blockSize; //向下取整 blockCount = floor(fa); if (bufferSize > blockSize) {//大於4M的文件 NSMutableData *sha2Data = [NSMutableData data]; for (int i = 0; i < blockCount+1; i++) { NSUInteger length = blockSize; if (i == blockCount && remainder > 0) { length = remainder; } //將每個塊(包括4M塊和小於4M的塊)進行sha1加密並拼接起來 NSData *subData = [data subdataWithRange:NSMakeRange(i * blockSize, length)]; [sha2Data appendData:[self sha1:subData]]; } //將拼接塊進行二次sha1加密 [sha1Data appendData:[self sha1:sha2Data]]; } else { [sha1Data appendData:[self sha1:data]]; } if (!sha1Data.length) return @"Fto5o-5ea0sNMlW_75VgGJCv2AcJ"; NSData *sha1Buffer = sha1Data; if (bufferSize > blockSize) { //大於4M,頭部拼接0x96單個位元組 prefix = 0x96; } Byte preByte[] = {prefix}; NSMutableData *mutaData = [NSMutableData dataWithBytes:preByte length:1]; [mutaData appendData:sha1Buffer]; //將長度為21個位元組的二進位數據進行url_safe_base64計算 return [self safeBase64WithSha1Str:mutaData]; } /* sha1加密(加密後的data長度為20) */ - (NSData*)sha1:(NSData *)data { //註:如果用以下代碼,轉換出的data長度為40 // const char *cstr = [sourceStr cStringUsingEncoding:NSUTF8StringEncoding]; // NSData *data = [NSData dataWithBytes:cstr length:sourceStr.length]; // NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2]; // for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) // [output appendFormat:@"%02x", digest[i]]; // return output; //sha1Data長度為20(CC_SHA1_DIGEST_LENGTH系統設定為20) uint8_t digest[CC_SHA1_DIGEST_LENGTH]; CC_SHA1(data.bytes, (CC_LONG)data.length, digest); NSData * sha1Data = [[NSData alloc] initWithBytes:digest length:CC_SHA1_DIGEST_LENGTH]; return sha1Data; } - (NSString *)safeBase64WithSha1Str:(NSData *)base64 { //Base64編碼中包含有"+,/,="不安全的URL字元串,我們要對這些字元進行轉換 NSString *base64Str = [GTMBase64 encodeBase64Data:base64]; NSMutableString *safeBase64Str = [[NSMutableString alloc] initWithString:base64Str]; safeBase64Str = (NSMutableString *)[safeBase64Str stringByReplacingOccurrencesOfString:@"+"withString:@"-"]; safeBase64Str = (NSMutableString *)[safeBase64Str stringByReplacingOccurrencesOfString:@"/"withString:@"_"]; safeBase64Str = (NSMutableString *)[safeBase64Str stringByReplacingOccurrencesOfString:@"="withString:@""]; return safeBase64Str; }
說明:url?stat可查看七牛文件的etag值(即hash值),如下:
http://yqq.file.mediportal.com.cn/yqq_5b911b43955f06317c6bd792/3974e8eaab11b2dd5b357e60e5a587d1?stat
{"fsize":687810,"uploaded":687810,"hash":"FtfVrVsdpVf9t_tCfyvsVC-1p6aW","mimeType":"image/jpeg"}