2010-10-04 8 views
8

Chunks Update 4
suggestion par Greg J'ai créé une paire de texte/image qui montre la sortie d'une image 37k à base64, en utilisant des morceaux 100k. Puisque le fichier est seulement 37k, il est prudent de dire que la boucle ne s'est répétée qu'une seule fois, donc rien n'a été ajouté. L'autre paire montre la sortie de la même image 37k à base64 codée, en utilisant des morceaux de 10k. Puisque le fichier est 37k, la boucle a été répétée quatre fois, et les données ont été définitivement ajoutées.base64 Encode fichier à l'aide NSData

Faire un diff sur les deux fichiers montre que sur le fichier de morceau de 10kb il y a une grande différence qui commence sur la ligne 214 et se termine sur la ligne 640.

Mise à jour 3
Voici où est mon code maintenant. Nettoyé un peu, mais en produisant le même effet:

 
// 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]]; 
} 

Mise à jour 2
Il semble donc que les fichiers qui sont plus de 100 KB se brouillées, mais les fichiers sous 100 KB sont très bien. Il est évident que quelque chose ne marche pas sur mon buffer/math/etc, mais je suis perdu sur celui-ci. Peut-être le temps de l'appeler un jour, mais j'aimerais aller dormir avec celui-ci résolu.

Voici un exemple:

Mise à jour 1
Après avoir fait quelques tests que j'ai trouvé que le même code fonctionne très bien pour une petite image, mais ne fonctionnera pas pour une grande image ou vidéo n'importe quelle taille. Vraiment ressemble à un problème de tampon, non? Hé là, essayant de coder en base64 un gros fichier en faisant une boucle et en faisant un petit morceau à la fois. Tout semble fonctionner mais les fichiers finissent toujours corrompus. J'étais curieux de savoir si quelqu'un pouvait indiquer où je pourrais aller mal ici:

 
    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

De quelle façon est la sortie corrompue? – Greg

+0

Pour les images (JPEG) et les vidéos (Quicktime), les fichiers sont illisibles. – frsh

+0

Ce qui me porte à croire qu'il y a quelque chose qui ne va pas avec mon offset. Lorsque j'utilise la même catégorie base64 sur NSData sans la diviser en morceaux, cela fonctionne très bien. – frsh

Répondre

2

Je voudrais pouvoir féliciter GregInYEG, parce que son point de départ sur le rembourrage était le problème sous-jacent. Avec base64, chaque morceau doit être un multiple de 3. Donc, ce résolu le problème:

chunkSize = 3600 

Une fois que j'avais que la corruption a disparu.Mais je suis tombé sur des problèmes de fuite de mémoire, alors j'ai ajouté la piscine autorelease apprach pris de ce poste: http://www.cocoadev.com/index.pl?ReadAFilePieceByPiece

Code final:

// 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

Hey @frsh ... Merci d'avoir posté la réponse mais le code semble incomplet (en particulier la boucle while) ... pouvez-vous s'il vous plaît poster le code complet si vous le pouvez ... Merci ... –

1

Comment se convertissent vous sauvegardez les données base64 à une image? Certaines implémentations limitent la longueur de ligne maximum qu'elles accepteront. Essayez d'insérer un saut de ligne tous les caractères.

+0

J'ai juste essayé d'ajouter une nouvelle ligne pour chaque boucle mais cela n'a pas fait de différence. – frsh

+0

Mais chaque itération de votre boucle compte plus de 25 000 caractères! Essayez quelque chose comme 80 caractères par ligne. – Aleph7

+0

OK, j'ai juste essayé d'ajouter newline tous les 80 caractères et j'ai obtenu le même résultat. Merci pour la suggestion cependant! – frsh