2012-06-11 8 views
9

Pracuję nad aplikacją Objective C Cocoa. Przetestowałem CC_MD5 in CommonCrypto i działało dobrze; jednak gdy dałem mu 5 plików gygabajtów, cały mój komputer zamarł i rozbił się. Algorytm MD5 przetwarza dane wejściowe w postaci 512-bajtowych porcji i nie wymaga od razu całego wejścia. Czy istnieje biblioteka w Objective C lub C, która prosi o następny 512-bajtowy fragment, zamiast pobierać wszystkie dane jednocześnie?Czy istnieje biblioteka MD5, która nie wymaga całego wejścia w tym samym czasie?

Odpowiedz

11

istnieje wielka nić na obliczenie MD5 dużych plików w obj-C tutaj: http://www.iphonedevsdk.com/forum/iphone-sdk-development/17659-calculating-md5-hash-large-file.html

Oto ktoś rozwiązanie wpadł tam:

+(NSString*)fileMD5:(NSString*)path 
{ 
    NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path]; 
    if(handle== nil) return @"ERROR GETTING FILE MD5"; // file didnt exist 

    CC_MD5_CTX md5; 

    CC_MD5_Init(&md5); 

    BOOL done = NO; 
    while(!done) 
    { 
     NSAutoreleasePool * pool = [NSAutoreleasePool new]; 
     NSData* fileData = [handle readDataOfLength: CHUNK_SIZE ]; 
     CC_MD5_Update(&md5, [fileData bytes], [fileData length]); 
     if([fileData length] == 0) done = YES; 
       [pool drain]; 
    } 
    unsigned char digest[CC_MD5_DIGEST_LENGTH]; 
    CC_MD5_Final(digest, &md5); 
    NSString* s = [NSString stringWithFormat: @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", 
        digest[0], digest[1], 
        digest[2], digest[3], 
        digest[4], digest[5], 
        digest[6], digest[7], 
        digest[8], digest[9], 
        digest[10], digest[11], 
        digest[12], digest[13], 
        digest[14], digest[15]]; 
    return s; 
} 
+0

Dzięki za link, przeczytanie go w tej chwili. –

+3

Ta odpowiedź skorzystałaby z aktualizacji dla ARC. Kod w pętli musi zostać umieszczony wewnątrz bloku '@autoreleasepool {}'. –

2

CC_MD5() jest przeznaczony do przetworzenia wszystkich jego wejście naraz. 5 GB jest prawdopodobnie więcej niż może faktycznie przechowywać w dowolnym miejscu. W przypadku większych danych, CommonCrypto może działać na porcjach w tym samym czasie, jeśli użyjesz CC_MD5_CTX, CC_MD5_Init(), CC_MD5_Update() i CC_MD5_Final(). Sprawdź dokumentację CommonCrypto lub Google, aby uzyskać więcej informacji i przykładowy kod.

2

Oto lepszy sposób, aby to zrobić za pomocą wysyłki apis, dla większej efektywności. Używam go w produkcji i działa dobrze!

#import "CalculateMD5.h" 

// Cryptography 
#include <CommonCrypto/CommonDigest.h> 

@implementation CalculateMD5 

- (id)init 
{ 
    self = [super init]; 
    if (self) 
    { 
     MD5ChecksumOperationQueue = dispatch_queue_create("com.test.calculateMD5Checksum", DISPATCH_QUEUE_SERIAL); 
    } 
    return self; 
} 

- (void)closeReadChannel 
{ 
    dispatch_async(MD5ChecksumOperationQueue, ^{ 
     dispatch_io_close(readChannel, DISPATCH_IO_STOP); 
    }); 
} 

- (void)MD5Checksum:(NSString *)pathToFile TCB:(void(^)(NSString *md5, NSError *error))tcb 
{ 
    // Initialize the hash object 
    __block CC_MD5_CTX hashObject; 
    CC_MD5_Init(&hashObject); 

    readChannel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, 
               pathToFile.UTF8String, 
               O_RDONLY, 0, 
               MD5ChecksumOperationQueue, 
               ^(int error) { 
                [self closeReadChannel]; 
               }); 

    if (readChannel == nil) 
    { 
     NSError* e = [NSError errorWithDomain:@"MD5Error" 
             code:-999 userInfo:@{ 
        NSLocalizedDescriptionKey : @"failed to open file for calculating MD5." 
         }]; 
     tcb(nil, e); 
     return; 
    } 

    dispatch_io_set_high_water(readChannel, 512*1024); 

    dispatch_io_read(readChannel, 0, SIZE_MAX, MD5ChecksumOperationQueue, ^(bool done, dispatch_data_t data, int error) { 
     if (error != 0) 
     { 
      NSError* e = [NSError errorWithDomain:@"ExamSoftMD5" 
              code:error userInfo:@{ 
         NSLocalizedDescriptionKey : @"failed to read from file for calculating MD5." 
          }]; 
      tcb(nil, e); 
      [self closeReadChannel]; 
      return; 
     } 

     if (dispatch_data_get_size(data) > 0) 
     { 
      const void *buffer = NULL; 
      size_t size = 0; 
      data = dispatch_data_create_map(data, &buffer, &size); 

      CC_MD5_Update(&hashObject, (const void *)buffer, (CC_LONG)size); 
     } 

     if (done == YES) 
     { 
      // Compute the hash digest 
      unsigned char digest[CC_MD5_DIGEST_LENGTH]; 
      CC_MD5_Final(digest, &hashObject); 

      // Compute the string result 
      char *hash = calloc((2 * sizeof(digest) + 1), sizeof(char)); 
      for (size_t i = 0; i < sizeof(digest); ++i) 
      { 
       snprintf(hash + (2 * i), 3, "%02x", (int)(digest[i])); 
      } 

      tcb(@(hash), nil); 

      [self closeReadChannel]; 
     } 
    }); 
} 


@end 
Powiązane problemy