Pregunta

Actualización 4
Por sugerencia de Greg He creado un par de imagen / texto que muestra la salida de una imagen de 37k a base64, utilizando trozos de 100k. Dado que el archivo sólo es 37k que es seguro decir que el bucle itera solamente una vez, por lo que nada se adjunta. Los otros espectáculos par la salida de la misma imagen 37k a base64 codificados, utilizando 10k trozos. Dado que el archivo es 37k del bucle itera cuatro veces, y los datos se anexa definitivamente.

haciendo diferencias en los dos archivos muestra que en el archivo 10kb trozo Hay una gran diferencia que comienza en la línea 214 y termina en la línea 640.

Actualización 3
Aquí es donde mi código es ahora. Limpiado un poco, pero sigue produciendo el mismo efecto:

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

Actualización 2
Así que parece que los archivos que son mayores que 100 KB consiguen revueltos, pero los archivos de menos de 100 KB están bien. Es obvio que algo está apagado en mi memoria intermedia / matemáticas / etc, pero estoy perdido en este caso. Podría ser el momento para llamar a un día, pero me encantaría ir a dormir con éste resuelto.

Este es un ejemplo:
Organizado por imgur.com

Actualización 1
Después de hacer algunas pruebas he encontrado que el mismo código funcionará bien para una imagen pequeña, pero no funcionará para una gran imagen o video de cualquier tamaño. Sin duda se ve como un problema de memoria intermedia, ¿verdad?


Hola, tratando de base64 codificar un archivo grande por un bucle a través y haciendo un pequeño trozo a la vez. Todo parece funcionar pero los archivos siempre terminan dañado. Tenía curiosidad si alguien podría señalar dónde podría ir mal aquí:

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

Solución

Me gustaría poder dar crédito a GregInYEG, porque su punto original sobre el relleno era la cuestión de fondo. Con base 64, cada trozo tiene que ser un múltiplo de 3. Así que esto resuelva el problema:

chunkSize = 3600

Una vez que tuve, la corrupción fue. Pero entonces me encontré con problemas de pérdida de memoria, por lo que añade la piscina apprach autorelease tomado de este 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];

Otros consejos

¿Cómo estás convirtiendo nuevo los datos base64 a una imagen? Algunas implementaciones limitan la longitud máxima de línea van a aceptar. Trate de insertar un salto de línea cada cierto número de caracteres.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top