写入文件不起作用

时间:2011-03-02 17:25:36

标签: objective-c cocoa macos

我正在尝试将应用中的图片合并到一个文件中并将其写入磁盘。

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

但两者都产生一个4KB(空)的文件。如果我NSLog错误,则为(null)。我是以错误的方式制作数据吗?

编辑:如果我用文本编辑器打开生成的文件,它看起来像这样: enter image description here

5 个答案:

答案 0 :(得分:4)

我写了一个简单的例子:
缺失:内存管理/错误处理/正确处理文件

// 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 :(得分:4)

回复以下评论:
因此,如果我只需要在运行时(在存档中)访问图像,是否有办法在索引处访问该图像而无需取消归档整个内容?对我来说似乎是不必要的开销。

我认为你还在努力解决这个问题? Hiding (or encrypting) app resources?

就像前面提到的那样,将所有文件合并为一个大文件就可以了 只需确保记住每个文件和文件顺序的文件长度 然后,您可以在不阅读整个文件的情况下提取您喜欢的任何特定文件 如果您当时只需要提取一个文件,这可能是更充分的方法。

快速'脏'样本:

// 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个字节包含所需信息 当您需要特定文件时:阅读索引,获取文件位置并将其解压缩。

答案 2 :(得分:1)

您正在归档NSImage的NSMutable数组。这两个类符合NSKeyedArchiver所要求的NSCoding协议,所以我看不出你的问题在哪里。
所以,这里有很多想法要测试。

首先,您确定您认为自己拥有的数据有效吗?在您的第一个代码段中,您可以编写[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取消归档文件?

答案 3 :(得分:1)

问题是[NSData dataWithContentsOfFile:@"0.png"]在当前目录中查找文件“0.png”,但是应用程序认为当前目录可能不是您期望的位置。对于图形应用程序,您应始终使用绝对路径或相对于某些可获取绝对路径的位置的路径(例如,您的应用程序包,应用程序支持目录,某些用户选择的位置)。

对于命令行工具,使用当前目录更为常见。但我怀疑是这种情况。

答案 4 :(得分:0)

我在小牛队注意到的另一件事是路径中的文件夹必须存在。这意味着您必须在保存到该文件夹​​之前创建文件夹结构。如果您尝试写入桌面或其他地方的文件夹,即使关闭了沙盒,如果该文件夹不存在,也会失败。我知道这已经得到了解答,但我发现我的问题仍然存在,但是一旦我确保文件夹结构到位,我就可以写到该文件夹​​了。

旁注:我确信你可以从NSFileManager那里做到这一点,一旦我最终确定我的应用程序结构,我将自己这样做,但希望这可以帮助其他人迷失方向。