在iOS应用中下载大文件 [英] Downloading a large file in iOS app

查看:53
本文介绍了在iOS应用中下载大文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试清理一些现有代码,这些代码将从服务器上分块下载一个大文件,检查每个50个数据包的校验和,然后将它们缝合在一起.我在查看它是否是最有效的方法时遇到了麻烦,因为由于内存问题,它现在崩溃了一段时间.如果我没有校验和,它似乎不会崩溃,但是如果我可以先检查我的文件,我会更希望.

I'm trying to clean up some existing code that downloads a large file from a server in chunks, checks the checksum on each 50 packets, then stitches them together. I'm having some trouble to see if it's the most efficient way as right now it crashes some time because of memory issues. If I don't have the checksum, it does not seem to crash, but I would prefer if I could check my files first.

@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;
}

checkFile和File的校验和只是从临时文件中获取校验和并进行比较.

The check checksum againstFile method just grabs the checksum from a temp file and compares it.

我阅读了有关NSAutoReleasePools的信息,以及如果您正在加载一堆图像并需要清除内存等信息,那将有什么帮助,但是我不确定这是否真的适用于此,以及是否有其他帮助下载的信息.一个大文件(少于1 GB).谢谢!

I read about NSAutoReleasePools and how that can help if you are loading a bunch of images and need to clear memory and such, but I wasn't sure if that really applies here and if that, or anything else can help in downloading a large file (a little less than 1 GB). Thanks!

推荐答案

一次在内存中保留大量数据肯定是一个问题.幸运的是,您不需要—您可以在断开连接时将数据写入磁盘,并且可以保持运行中的校验和.

Keeping that much data in memory at once is definitely going to be a problem. Fortunately, you don't need to—you can write the data to disk as it comes off the wire, and you can keep a running checksum.

将您的ReceivedData换成两个新的ivars:

Trade your ReceivedData for a couple of new ivars:

NSFileHandle* filehandle;
MD5_CTX md5sum;

MD5_CTX在OpenSSL中,但…在iOS上还不存在?加.好的,您可以在线找到MD5来源,例如此处: http://people.csail.mit.edu/rivest/Md5.c (我d最初建议在您的项目中添加OpenSSL,但这不是您所需要的很多额外的垃圾.但是,如果您碰巧已经在使用OpenSSL,则它包括MD5函数.)

MD5_CTX is in OpenSSL, which …still isn't on iOS? Gah. Okay, you can find the MD5 source online, e.g. here: http://people.csail.mit.edu/rivest/Md5.c (I'd originally suggested adding OpenSSL to your project, but that's a lot of extra junk that you don't need. But if you happen to already be using OpenSSL, it includes the MD5 functions.)

- (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的总和,而您几乎将不会使用任何内存.

At the end, your file will be on disk, you'll have its MD5 sum, and you'll barely be using any memory at all.

这篇关于在iOS应用中下载大文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆