Запись в файл не работает - PullRequest
3 голосов
/ 02 марта 2011

Я пытаюсь объединить изображения из моего приложения в один файл и записать его на диск.

NSMutableArray *array = [NSMutableArray arrayWithObjects: 
                         [NSData dataWithContentsOfFile:@"0.png"], 
                         [NSData dataWithContentsOfFile:@"1.png"],
                         [NSData dataWithContentsOfFile:@"2.png"],
                         nil];

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
NSError *error = nil;
NSString *path=@"/Users/myusername/Desktop/_stuff.dat";
[data writeToFile:path options:NSDataWritingAtomic error:&error];

или

NSArray *array = [NSArray arrayWithObjects:
                  [NSImage imageNamed:@"0"], 
                  [NSImage imageNamed:@"1"], 
                  [NSImage imageNamed:@"2"], 
                  nil];

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
NSError *error = nil;
NSString *path=@"/Users/myusername/Desktop/_stuff.dat";
[data writeToFile:path options:NSDataWritingAtomic error:&error];

Но оба файла создают файл размером 4 КБ (пустой).Если я NSLog ошибка, то это (null).Я неправильно делаю данные?

Редактировать: Если я открываю полученный файл в текстовом редакторе, он выглядит так: enter image description here

Ответы [ 5 ]

4 голосов
/ 04 марта 2011

Ответ на следующий комментарий:
Так что, если мне нужен только доступ к изображению во время выполнения (в архиве), есть ли способ получить доступ к этому изображению по индексу, не разархивировав его целиком? Мне кажется, это лишние накладные расходы.

Полагаю, вы все еще боретесь с этой проблемой?
Скрытие (или шифрование) ресурсов приложения?

Как я упоминал ранее, объединение всех файлов в один большой файл делает свое дело.
Просто убедитесь, что вы помните длину каждого файла и порядок файлов.
Затем вы можете извлечь любой определенный файл, не читая весь файл.
Это может быть более подходящим способом, если вам нужно извлечь только один файл за раз.

Быстрый «грязный» образец:

// Two sample files
NSData *fileOne = [NSData dataWithContentsOfFile:@"/Users/Anne/Desktop/1.png"];
NSData *fileTwo = [NSData dataWithContentsOfFile:@"/Users/Anne/Desktop/2.png"];

// Get file length
int  fileOneLength = [fileOne length];
int  fileTwoLength = [fileTwo length];

// Combine files into one container
NSMutableData * container = [[NSMutableData alloc] init];
[container appendData:fileOne];
[container appendData:fileTwo];

// Write container to disk
[container writeToFile:@"/Users/Anne/Desktop/container.data" atomically:YES];

// Read data and extract sample files again
NSData *containerFile = [NSData dataWithContentsOfFile:@"/Users/Anne/Desktop/container.data"];
NSData *containerFileOne =[containerFile subdataWithRange:NSMakeRange(0, fileOneLength)];
NSData *containerFileTwo =[containerFile subdataWithRange:NSMakeRange(fileOneLength, fileTwoLength)];

// Write extracted files to disk (will be exactly the same)
[containerFileOne writeToFile:@"/Users/Anne/Desktop/1_extracted.png" atomically:YES];
[containerFileTwo writeToFile:@"/Users/Anne/Desktop/2_extracted.png" atomically:YES];

// Only extract one file from the container
NSString * containerPath = @"/Users/Anne/Desktop/container.data";
NSData * oneFileOnly = [[NSFileHandle fileHandleForReadingAtPath:containerPath] readDataOfLength:fileOneLength]; 

// Write result to disk
[oneFileOnly writeToFile:@"/Users/Anne/Desktop/1_one_file.png" atomically:YES];

Совет: Вы также можете сохранить индекс внутри файла контейнера.
Например: первые 500 байтов содержат необходимую информацию.
Когда вам нужен конкретный файл: прочитайте указатель, найдите позицию файла и извлеките его.

4 голосов
/ 03 марта 2011

Я написал быстрый пример:
Отсутствует: управление памятью / обработка ошибок / правильная обработка файлов

// Archive

NSMutableArray *array = [[NSMutableArray alloc] init];

NSString * input = @"/Users/Anne/Desktop/1.png";

[array addObject:[NSData dataWithContentsOfFile:input]];
[array addObject:[NSData dataWithContentsOfFile:input]];
[array addObject:[NSData dataWithContentsOfFile:input]];

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
NSString *path = @"/Users/Anne/Desktop/archive.dat";
[data writeToFile:path options:NSDataWritingAtomic error:nil];


// Unarchive

NSMutableArray *archive = [NSKeyedUnarchiver unarchiveObjectWithFile:path];

NSData * firstObject = [archive objectAtIndex:0];
NSString * output = @"/Users/Anne/Desktop/2.png";
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:output];
[firstObject writeToURL:fileURL atomically:YES];

Вы также можете добавить NSImages в NSMutableArray:

NSString * input = @"/Users/Anne/Desktop/1.png";
NSImage *image = [[NSImage alloc] initWithContentsOfFile: input];
[array addObject:image];

Но это значительно увеличит размер файла.

1 голос
/ 03 марта 2011

Проблема в том, что [NSData dataWithContentsOfFile:@"0.png"] ищет файл "0.png" в текущем каталоге, но то, что приложение считает текущим каталогом, вероятно, не место, которое вы ожидаете.Для графических приложений вы всегда должны использовать либо абсолютный путь, либо путь относительно некоторого места, в котором вы можете получить абсолютный путь (например, ваш комплект приложений, каталог поддержки приложений, какое-то выбранное пользователем местоположение).

Для инструментов командной строки более часто используется текущий каталог.Но я сомневаюсь, что это так.

1 голос
/ 02 марта 2011

Вы архивируете массив NSMutable NSImage.Эти два класса соответствуют протоколу NSCoding, требуемому NSKeyedArchiver, поэтому я не вижу, где будет ваша проблема.
Итак, вот много идей для тестирования.

Во-первых, вы уверены, что данныеВы думаете, что действительны?В своем первом фрагменте кода вы пишете [NSData dataWithContentsOfFile:@"0.png"].Этот метод ожидает абсолютный путь к файлу.

Предполагая, что проблема не в вашем коде, просто в вашем вопросе, давайте продолжим:

У вас есть что-то отличное от nil в переменных данных после вашегоархивирование?Т.е. после присвоения данным можно добавить этот код.Если утверждение не выполнено, вы получите исключение во время выполнения:

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
NSAssert(nil != data, @"My object data is nil after archiving");

Если проблема была не в этом, что означает возврат строки [data writeToFile:path options:NSDataWritingAtomic error:&error];
(Не ошибка переменной, авернуть значение вызова метода - writeToFile: options: error:)

Что произойдет, если вы упростите свой код и просто сделаете это:

result = [NSKeyedArchiver archiveRootObject:data
                                     toFile:archivePath];

Если все было в порядке, вы пытались разархивировать свойфайл с помощью NSKeyedUnarchiver?

0 голосов
/ 09 августа 2014

Еще одна вещь, которую я заметил на Mavericks и выше, это то, что папки в пути должны существовать. Это означает, что вы должны создать структуру папок перед сохранением в эту папку. Если вы попытаетесь выполнить запись в папку на рабочем столе или в другом месте, даже если песочница отключена, произойдет сбой, если папка не существует. Я знаю, что на этот вопрос уже был дан ответ, но я обнаружил, что моя проблема продолжалась независимо, но как только я удостоверился, что структура папок была создана, я мог сделать свою запись в эту папку.

На заметку: я уверен, что вы можете сделать это из NSFileManager, и я сделаю это сам, как только завершу работу над структурой приложения, но надеюсь, что это поможет кому-то еще потерянному в соусе.

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