2010-10-04 17 views
8

Update 4
sugestię Per Grega Utworzyłem jedną parę obraz/tekst, który pokazuje wyjścia z 37K obrazu do base64 kodowanych przy użyciu 100k kawałki. Ponieważ plik ma tylko 37 KB, można bezpiecznie powiedzieć, że pętla jest tylko iterowana raz, więc nic nie zostało dodane. Druga para pokazuje dane wyjściowe z tego samego obrazu 37k na kodowane base64, używając 10k porcji. Ponieważ plik ma rozmiar 37k, pętla wykonywana była czterokrotnie, a dane zostały ostatecznie dołączone.Base64 Kodowanie pliku Korzystanie NSData Kawałki

Doing diff na dwóch plików pokazuje, że plik 10kB bryłkach istnieje duża różnica, która zaczyna się na linii 214 i kończy się na linii 640.

Aktualizacja 3
Oto gdzie jest mój kod. Oczyścić trochę ale nadal produkował ten sam efekt:

 
// Read data in chunks from the original file 
[originalFile seekToEndOfFile]; 
NSUInteger fileLength = [originalFile offsetInFile]; 
[originalFile seekToFileOffset:0]; 
NSUInteger chunkSize = 100 * 1024; 
NSUInteger offset = 0; 

while(offset < fileLength) { 
    NSData *chunk = [originalFile readDataOfLength:chunkSize]; 
    offset += chunkSize; 

    // Convert the chunk to a base64 encoded string and back into NSData 
    NSString *base64EncodedChunkString = [chunk base64EncodedString]; 
    NSData *base64EncodedChunk = [base64EncodedChunkString dataUsingEncoding:NSASCIIStringEncoding]; 

    // Write the encoded chunk to our output file 
    [encodedFile writeData:base64EncodedChunk]; 

    // Cleanup 
    base64EncodedChunkString = nil; 
    base64EncodedChunk = nil; 

    // Update progress bar 
    [self updateProgress:[NSNumber numberWithInt:offset] total:[NSNumber numberWithInt:fileLength]]; 
} 

Aktualizacja 2
Tak wygląda plików, które są większe niż 100 KB dostać jajecznicę, ale pliki poniżej 100 KB są w porządku. Jest oczywiste, że coś jest wyłączone na moim buforze/matematyce/etc, ale jestem zagubiony na tym. Być może nadszedł czas, aby nazwać to dzień, ale chciałbym iść spać z tym rozwiązanym.

Oto przykład:

Update 1
Po wykonaniu niektórych badań odkryłem, że ten sam kod będzie działać dobrze dla małego obrazka, ale nie będzie działać dla dużego obrazu lub wideo dowolny rozmiar. Zdecydowanie wygląda na problem z buforem, prawda?


Hej tam, próbując base64 zakodować duży plik, wykonując pętlę i wykonując jedną małą porcję na raz. Wszystko wydaje się działać, ale pliki zawsze są uszkodzone. Byłem ciekawy, czy ktoś może wskazać, gdzie może być nie tak tutaj:

 
    NSFileHandle *originalFile, *encodedFile; 
    self.localEncodedURL = [NSString stringWithFormat:@"%@-base64.xml", self.localURL]; 

    // Open the original file for reading 
    originalFile = [NSFileHandle fileHandleForReadingAtPath:self.localURL]; 
    if (originalFile == nil) { 
     [self performSelectorOnMainThread:@selector(updateStatus:) withObject:@"Encoding failed." waitUntilDone:NO]; 
     return; 
    } 
    encodedFile = [NSFileHandle fileHandleForWritingAtPath:self.localEncodedURL]; 
    if (encodedFile == nil) { 
     [self performSelectorOnMainThread:@selector(updateStatus:) withObject:@"Encoding failed." waitUntilDone:NO]; 
     return; 
    } 

    // Read data in chunks from the original file 
    [originalFile seekToEndOfFile]; 
    NSUInteger length = [originalFile offsetInFile]; 
    [originalFile seekToFileOffset:0]; 
    NSUInteger chunkSize = 100 * 1024; 
    NSUInteger offset = 0; 
    do { 
     NSUInteger thisChunkSize = length - offset > chunkSize ? chunkSize : length - offset; 
     NSData *chunk = [originalFile readDataOfLength:thisChunkSize]; 
     offset += [chunk length]; 

     NSString *base64EncodedChunkString = [chunk base64EncodedString]; 
     NSData *base64EncodedChunk = [base64EncodedChunkString dataUsingEncoding:NSASCIIStringEncoding]; 

     [encodedFile writeData:base64EncodedChunk]; 

     base64EncodedChunkString = nil; 
     base64EncodedChunk = nil; 

    } while (offset < length); 
+0

W jaki sposób wyjście uszkodzony? – Greg

+0

Dla obu obrazów (JPEG) i wideo (QuickTime) pliki są nieczytelne. – frsh

+0

Co prowadzi mnie do przekonania, że ​​coś jest nie tak z moim offsetem. Kiedy używam tej samej kategorii base64 na NSData bez dzielenia jej na porcje, to działa dobrze. – frsh

Odpowiedz

2

Chciałabym móc przyznać GregInYEG, ponieważ jego pierwotnym punktem dotyczącym dopełnienia był podstawowy problem. W wersji base64 każda porcja musi być wielokrotnością 3. Rozwiązało to problem:

chunkSize = 3600 

Kiedy raz to miałem, korupcja odeszła.Ale potem wpadłem na kwestiach wycieków pamięci, więc dodałem basen apprach autorelease pobrane z tego postu: http://www.cocoadev.com/index.pl?ReadAFilePieceByPiece

kod końcowa:

// Read data in chunks from the original file 
[originalFile seekToEndOfFile]; 
NSUInteger fileLength = [originalFile offsetInFile]; 
[originalFile seekToFileOffset:0]; 

// For base64, each chunk *MUST* be a multiple of 3 
NSUInteger chunkSize = 24000; 
NSUInteger offset = 0; 
NSAutoreleasePool *chunkPool = [[NSAutoreleasePool alloc] init]; 

while(offset < fileLength) { 
    // Read the next chunk from the input file 
    [originalFile seekToFileOffset:offset]; 
    NSData *chunk = [originalFile readDataOfLength:chunkSize]; 

    // Update our offset 
    offset += chunkSize; 

    // Base64 encode the input chunk 
    NSData *serializedChunk = [NSPropertyListSerialization dataFromPropertyList:chunk format:NSPropertyListXMLFormat_v1_0 errorDescription:NULL]; 
    NSString *serializedString = [[NSString alloc] initWithData:serializedChunk encoding:NSASCIIStringEncoding]; 
    NSRange r = [serializedString rangeOfString:@"<data>"]; 
    serializedString = [serializedString substringFromIndex:r.location+7]; 
    r = [serializedString rangeOfString:@"</data>"]; 
    serializedString = [serializedString substringToIndex:r.location-1]; 

    // Write the base64 encoded chunk to our output file 
    NSData *base64EncodedChunk = [serializedString dataUsingEncoding:NSASCIIStringEncoding]; 
    [encodedFile truncateFileAtOffset:[encodedFile seekToEndOfFile]]; 
    [encodedFile writeData:base64EncodedChunk]; 

    // Cleanup 
    base64EncodedChunk = nil; 
    serializedChunk = nil; 
    serializedString = nil; 
    chunk = nil; 

    // Update the progress bar 
    [self updateProgress:[NSNumber numberWithInt:offset] total:[NSNumber numberWithInt:fileLength]]; 

    // Drain and recreate the pool 
    [chunkPool release]; 
    chunkPool = [[NSAutoreleasePool alloc] init]; 
} 
[chunkPool release]; 
+0

Hej @ frsh ... Dzięki za napisanie odpowiedzi, ale kod wygląda niekompletnie (szczególnie pętla while) ... czy możesz opublikować pełny kod, jeśli potrafisz ... Dzięki ... –

1

Jak ty Nawrócenie dane base64 do obrazu? Niektóre implementacje ograniczają maksymalną długość linii, którą zaakceptują. Spróbuj wstawić podział linii co tylu znaków.

+0

Po prostu spróbowałem dodać znak nowej linii dla każdej pętli, ale to nie miało znaczenia. – frsh

+0

Ale każda iteracja w twojej pętli ma ponad 25 000 znaków! Spróbuj około 80 znaków w linii. – Aleph7

+0

OK, po prostu próbowałem dodawać znak nowej linii co 80 znaków i otrzymałem taki sam wynik. Dzięki za sugestię! – frsh