3

サーバーから大きなファイルをチャンクでダウンロードし、50 パケットごとにチェックサムをチェックし、それらをつなぎ合わせる既存のコードをクリーンアップしようとしています。現在、メモリの問題のためにしばらくクラッシュするため、それが最も効率的な方法であるかどうかを確認するのに問題があります。チェックサムがなくてもクラッシュしないように見えますが、最初にファイルをチェックできればと思います。

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

check checksum againstFile メソッドは、一時ファイルからチェックサムを取得して比較します。

私は NSAutoReleasePools について読み、大量の画像を読み込んでメモリをクリアする必要がある場合にどのように役立つかを読みましたが、それが本当にここに当てはまるかどうか、またそれが大きなファイルのダウンロードに役立つかどうかはわかりませんでした(1 GB 弱)。ありがとう!

4

1 に答える 1

6

一度に大量のデータをメモリに保持することは、間違いなく問題になります。幸いなことに、その必要はありません。データがネットワークから離れたときにディスクに書き込むことができ、実行中のチェックサムを保持できます。

ReceivedData をいくつかの新しい ivar と交換します。

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 サムがあり、メモリをほとんど使用していません。

于 2012-05-08T16:52:53.300 に答える