Pergunta

Atualização 4
De acordo com a sugestão de Greg, criei um par de imagens/texto que mostra a saída de uma imagem de 37k para base64 codificada, usando pedaços de 100k. Como o arquivo tem apenas 37k, é seguro dizer que o loop apenas iterou uma vez, então nada foi anexado. O outro par mostra a saída da mesma imagem de 37k para base64 codificada, usando pedaços de 10k. Como o arquivo é 37k, o loop iterou quatro vezes e os dados foram definitivamente anexados.

Fazendo um diferencial nos dois arquivos mostra que, no arquivo de chunk de 10kb, há uma grande diferença que começa na linha 214 e termina na linha 640.

Atualização 3
Aqui é onde está meu código agora. Limpou um pouco, mas ainda produzindo o mesmo efeito:

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

Atualização 2
Portanto, parece que os arquivos maiores que 100 kb são embaralhados, mas os arquivos abaixo de 100 kb são bons. É óbvio que algo está errado no meu buffer/matemática/etc, mas estou perdido neste. Pode ser hora de encerrar o dia, mas eu adoraria dormir com este resolvido.

Aqui está um exemplo:

Atualização 1
Depois de fazer alguns testes, descobri que o mesmo código funcionará bem para uma imagem pequena, mas não funcionará para uma imagem ou vídeo grande de qualquer tamanho. Definitivamente parece uma questão de buffer, certo?


Olá, tentando base64 codificar um arquivo grande, atravessando e fazendo um pequeno pedaço de cada vez. Tudo parece funcionar, mas os arquivos sempre acabam corrompidos. Fiquei curioso se alguém pudesse apontar onde eu poderia estar errado aqui:

    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);
Foi útil?

Solução

Eu gostaria de poder dar crédito a Greginyeg, porque seu ponto original sobre o preenchimento era a questão subjacente. Com base64, cada pedaço deve ser um múltiplo de 3. Portanto, isso resolveu o problema:

chunkSize = 3600

Depois que eu tive isso, a corrupção foi embora. Mas então eu encontrei problemas de vazamento de memória, então adicionei o AutorEleasease Pool Aproach retirado deste post: http://www.cocoadev.com/index.pl?readafilepiecebypiece

Código 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];

Outras dicas

Como você está convertendo os dados BASE64 em uma imagem? Algumas implementações limitam o comprimento máximo da linha que aceitarão. Tente inserir uma quebra de linha todos os tantos personagens.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top