Objective c 写入文件不工作

Objective c 写入文件不工作,objective-c,cocoa,macos,Objective C,Cocoa,Macos,我正在尝试将应用程序中的图像合并到一个文件中,并将其写入磁盘 NSMutableArray *array = [NSMutableArray arrayWithObjects: [NSData dataWithContentsOfFile:@"0.png"], [NSData dataWithContentsOfFile:@"1.png"],

我正在尝试将应用程序中的图像合并到一个文件中,并将其写入磁盘

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

但两者都会生成4KB(空)的文件。如果我
NSLog
出错,它就是
(null)
。我是否以错误的方式生成数据

编辑:如果我用文本编辑器打开生成的文件,它如下所示:

您正在存档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:nsdatawriteingatomic error:&error]的返回是什么
(不是变量error,而是方法调用的返回值
-writeToFile:options:error:

如果简化代码并只执行以下操作,会发生什么情况:

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

如果一切正常,您是否尝试使用NSKeyedUnarchiver解除文件归档?

我写了一个快速示例:
缺少:内存管理/错误处理/正确的文件处理

您还可以将NSImage添加到NSMutableArray:

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

但这会显著增加文件大小。

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


对于命令行工具,使用当前目录更为常见。但我对此表示怀疑。

对以下评论的回应:

因此,如果我只需要在运行时(在存档中)访问一个图像,有没有一种方法可以在索引中访问该图像而不必取消整个存档?对我来说似乎不必要的开销

我想你还在努力解决这个问题?

正如我前面提到的,将所有文件合并成一个大文件就可以了。
只需确保记住每个文件的文件长度和文件顺序。
然后,您可以提取您喜欢的任何特定文件,而无需读取整个文件。
如果一次只需要提取一个文件,这可能是一种更充分的方法

快速“脏”样本:

// 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个字节包含所需信息。

当您需要一个特定的文件时:读取索引,获取文件位置并将其解压缩。

我在Mavericks和更高版本上注意到的另一件事是路径中的文件夹必须存在。这意味着您必须在保存到该文件夹之前创建文件夹结构。如果尝试写入桌面或其他位置的文件夹,即使关闭了沙箱,如果该文件夹不存在,也会失败。我知道这个问题已经得到了回答,但我发现我的问题仍然存在,但一旦我确定文件夹结构已就位,我就可以对该文件夹进行写作了


顺便说一句:我相信你可以从NSFileManager中完成这项工作,一旦我确定了我的应用程序结构,我将自己完成这项工作,但希望这能帮助其他陷入困境的人

您不应该像那样硬编码路径。使用
[NSHomeDirectory()stringByAppendingPathComponent:@“Desktop/_stuff.dat”]
甚至
[[NSHomeDirectory()stringByAppendingPathComponent:@“桌面”]stringByAppendingPathComponent:@“\u stuff.dat”]@Rob谢谢你的提示。这是一个一次性使用的代码,我正在使用它将图像分组到一个大文件中,仅供我个人使用。不过,我会记住的!谢谢你的编辑,我今天晚些时候访问我的代码时会尝试。你通过告诉我绝对路径修复了我的部分问题。我使用的是相对路径,但它不起作用。谢谢你的帮助。是的,纪尧姆帮助我理解了这一点。我习惯于让操作系统自动为我查找文件,但我以前从未使用过绝对路径。因此,如果我只需要在运行时(在存档中)访问一个映像,有没有一种方法可以在索引处访问该映像而不必取消整件事的存档?对我来说,这似乎是不必要的开销。请参阅我的第二个答案(此评论太长)。
NSString * input = @"/Users/Anne/Desktop/1.png";
NSImage *image = [[NSImage alloc] initWithContentsOfFile: input];
[array addObject:image];
// 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];