2012-05-08 34 views
3

我在尝试清理一些现有的代码,它以大块的形式从服务器下载大文件,检查每个50包的校验和,然后将它们拼接在一起。我遇到了一些麻烦,看看它是否是最有效的方式,因为内存问题,现在它会崩溃一段时间。如果我没有校验和,它似乎不会崩溃,但我宁愿如果我可以先检查我的文件。在iOS应用程序中下载大文件

@property (nonatomic, retain) NSMutableData * ReceivedData; 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection { 

NSData *sequencePacketData = [[NSData alloc] initWithData:self.ReceivedData]; 
     [self ProcessPacket:sequencePacketData]; 
     [sequencePacketData release]; 
     [[NSNotificationCenter defaultCenter] postNotificationName:DownloadNotification object:self]; 

} 

- (void)ProcessPacket:(NSData *)sequencePacketData { 
    // find the directory I need to write to and the name of the file 
NSString *currentChecksum = [WebServiceManager MD5CheckSumForNSData:sequencePacketData]; 
    BOOL checkSumValid = [dmgr ValidateChecksum:currentChecksum againstFileName:self.CurrentFileName]; 
    self.IsSuccessful = checkSumValid; 

    if (!checkSumValid) { 
     // log error msg 
     return; 
    } 

    if (success) 
    { 
     NSFileHandle *handle = [NSFileHandle fileHandleForUpdatingAtPath:sequencePath]; 
     [handle seekToEndOfFile]; 
     [handle writeData:sequencePacketData]; 
     [handle closeFile]; 
    } 
    else 
    { 
     [sequencePacketData writeToFile:sequencePath atomically:YES]; 
    } 

    // When file is completely downloaded, check the checksum of the entire file: 
BOOL completeFileCheckSum; 
    if ([packetFile isEqualToString:@"50.bin"]) { 
     NSData *temData = [NSData dataWithContentsOfFile:sequencePath]; 
     currentChecksum = [WebServiceManager MD5CheckSumForNSData:temData]; 
     completeFileCheckSum = [dmgr ValidateChecksum:currentChecksum againstFileName:fileName]; 
     NSLog(@"Checksum for whole file is valid: %i", completeFileCheckSum); 
     if (!completeFileCheckSum) { 
      NSError *err; 
      [fileManager removeItemAtPath:sequencePath error:&err]; 

      // log error 
      return; 
     } 
    } 
} 

+ (NSString*)MD5CheckSumForNSData:(NSData *) input 
{ 
    // Create byte array of unsigned chars 
    unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH]; 

    // Create 16 byte MD5 hash value, store in buffer 
    CC_MD5(input.bytes, input.length, md5Buffer); 

    // Convert unsigned char buffer to NSString of hex values 
    NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; 
    for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) 
     [output appendFormat:@"%02x",md5Buffer[i]]; 
    return output; 
} 

检查校验和againstFile方法只是从临时文件抓取校验和并对其进行比较。

我阅读了关于NSAutoReleasePools以及如何加载一堆图像并清除内存等方面的信息,但我不确定这是否真的适用于此,如果这样或其他可以帮助您下载一个大文件(少于1 GB)。谢谢!

回答

6

把这么多的数据一次保存在内存中肯定会成为一个问题。幸运的是,您不需要 - 您可以将数据写入磁盘,因为它离开电线,并且可以保持运行的校验和。

贸易的一对夫妇的新的ivars ReceivedData:

NSFileHandle* filehandle; 
MD5_CTX md5sum; 

MD5_CTX是OpenSSL的,这......还不是iOS上?嘎。好的,您可以在线找到MD5源,例如这里:http://people.csail.mit.edu/rivest/Md5.c(我原本建议在你的项目中加入OpenSSL,但是这是你不需要的额外垃圾,但如果你碰巧已经在使用OpenSSL,那么它包含了MD5功能。)

- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response 
{ 
    MD5Init(&md5sum); 

    filehandle = [[NSFileHandle filehandleForWritingAtPath:path] retain]; 
} 

- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data 
{ 
    MD5Update(&md5sum, [data bytes], [data length]); 

    [filehandle writeData:data]; 
} 

- (void)connectionDidFinishLoading:(NSURLConnection*)connection 
{ 
    MD5Final(&md5sum); 
    // MD5 sum is in md5sum.digest[] 

    [filehandle closeFile]; 

    // verify MD5 sum, etc.. 
} 

最后,你的文件将在磁盘上,你将得到它的MD5总和,你几乎不会使用任何内存。

+3

实际上它来自iOS 5以后的'#import ',其类型和函数为'CC_MD5_CTX','CC_MD5_Init','CC_MD5_Update'和'CC_MD5_Final'。 – NebulaFox

+1

这里是头文件http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-36064/CommonCrypto/CommonDigest.h – NebulaFox

+0

很高兴知道。谢谢! – davehayden

相关问题