Base64使用NSData块编码文件

时间:2010-10-04 21:55:04

标签: iphone objective-c base64 nsdata nsfilehandle

更新4
根据Greg的建议,我创建了一对图像/文本,使用100k块显示从37k图像到base64编码的输出。由于文件只有37k,所以可以说循环只迭代一次,因此没有附加任何内容。另一对使用10k块显示从相同的37k图像到base64编码的输出。由于文件是37k,循环迭代四次,并且数据被明确附加。

对这两个文件进行差异显示,在10kb的块文件中,差异很大,从第214行开始,到第640行结束。

更新3
这是我的代码现在的位置。清理了一下,但仍产生同样的效果:

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

更新2
因此看起来大于100 KB的文件会被扰乱,但100 KB以下的文件很好。显而易见,我的缓冲区/数学/等等有些东西已经关闭,但我在这个问题上迷失了。可能是时候把它称为一天,但我很想睡觉,这个解决了。

以下是一个例子:

更新1
经过一些测试后,我发现相同的代码可以很好地处理小图像,但不适用于任何大小的大图像或视频。绝对看起来像一个缓冲区问题,对吗?


嘿那里,尝试通过循环遍历并对一个小块进行一次编码来对base64进行编码。一切似乎都有效,但文件总是被破坏了。我很好奇是否有人能指出我在哪里可能会出错:

    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);

2 个答案:

答案 0 :(得分:2)

我希望我能够赞扬GregInYEG,因为他关于填充的原始观点是潜在的问题。使用base64,每个块必须是3的倍数。因此,这解决了问题:

chunkSize = 3600

一旦我这样做,腐败就消失了。但后来我遇到了内存泄漏问题,所以我添加了从这篇文章中获取的自动释放池评论: http://www.cocoadev.com/index.pl?ReadAFilePieceByPiece

最终代码:

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

答案 1 :(得分:1)

如何将base64数据转换回图像?某些实现限制了它们将接受的最大行长度。尝试每隔这么多字符插入换行符。