Question

Mise à jour 4 Par la suggestion de Greg J'ai créé une paire de texte / image qui montre la sortie d'une image de 37k à base64, en utilisant des morceaux 100k. Étant donné que le fichier est seulement 37k il est sûr de dire une fois que la boucle n'itérer, donc rien n'a été ajouté. Les autres séries de paires de la sortie à partir de la même image de 37k à base64 codés, en utilisant des morceaux 10k. Étant donné que le fichier est 37k la boucle itérer quatre fois, et les données ont été sans aucun doute ajouté.

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ù mon code est 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 de moins de 100 Ko sont très bien. Il est évident que quelque chose est hors de mon tampon / math / etc, mais je suis perdu sur celui-ci. Peut-être le temps de l'appeler un jour, mais je serais ravi d'aller dormir avec celui-ci résolu.

Voici un exemple:
Hébergé par imgur.com

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 de toute taille. ressemble vraiment à un problème de mémoire tampon, non?


Hé là, en essayant de base64 encoder un fichier volumineux par une boucle à travers et faire un petit morceau à la fois. Tout semble fonctionner, mais les fichiers finissent toujours corrompu. 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);
Était-ce utile?

La solution

Je souhaite que je pourrais donner crédit à GregInYEG, parce que son point d'origine sur le remplissage était le problème sous-jacent. Avec base64, chaque morceau doit être un multiple de 3. Donc, ce a résolu le problème:

chunkSize = 3600

Une fois que j'avais que la corruption est allé loin. Mais je suis tombé sur des problèmes de fuite de mémoire, alors j'ai ajouté la apprach piscine autorelease prise 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];

Autres conseils

Comment convertissez vous sauvegardez les données base64 à une image? Certaines implémentations limitent la longueur de ligne maximale qu'ils accepteront. Essayez d'insérer une ligne briser tous tant de caractères.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top