Файл кодирования Base64 с использованием фрагментов NSData - PullRequest
8 голосов
/ 05 октября 2010

Обновление 4 Согласно предложению Грега, я создал одну пару изображения / текста, которая отображает выходные данные из изображения 37 КБ в кодировке Base64, используя куски по 100 КБ.Поскольку размер файла составляет всего 37 Кбайт, можно сказать, что цикл повторяется только один раз, поэтому ничего не добавлялось.Другая пара показывает вывод из того же 37k-изображения в кодировку base64, используя 10k-фрагменты.Поскольку размер файла составляет 37 КБ, цикл повторяется четыре раза, и данные определенно добавляются.

Выполнение различий для двух файлов показывает, что в файле фрагмента размером 10 КБ существует большая разница, которая начинается в строке 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 КБ выглядят зашифрованными, но файлы размером менее 100 КБ вполне подойдут.Очевидно, что что-то не так в моем буфере / математике / и т.д., но я потерян на этом.Возможно, настало время назвать это днем, но я бы хотел пойти спать с этим решенным.

Вот пример:Хостинг imgur.com

Обновление 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 ]

2 голосов
/ 06 октября 2010

Хотелось бы отдать должное 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 голос
/ 05 октября 2010

Как вы конвертируете данные base64 в изображение? Некоторые реализации ограничивают максимальную длину строки, которую они принимают. Попробуйте вставить разрыв строки через столько символов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...