如何在 iPhone 上获得可写路径?

我发布这个问题,因为我有一个完整的答案写出来的另一个职位,当我发现它不适用于原来的,但我认为是太有用的浪费。因此,我也把它作为一个社区维基,这样其他人就可以充实问答了。如果你觉得这个答案有用,请投票给这个问题-作为一个社区维基我不应该得到这个投票点,但它会帮助其他人找到它

我怎样才能得到一个路径到哪些文件写允许在 iPhone 上?你可以(误导性地)在 Simulator 上写任何你想写的东西,但是在 iPhone 上你只能写到特定的位置。

43068 次浏览

有三种可写路径需要考虑——第一种是 Document,你可以在其中存储你想要保存的东西,并通过 iTunes (从3.2版本开始)提供给用户:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

其次,和文档目录非常相似,有一个 Library 文件夹,你可以在其中存储配置文件和可写数据库,你也想保留这些文件,但是你不想让用户在 iTunes 上乱搞:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *libraryDirectory = [paths objectAtIndex:0];

请注意,即使用户不能使用超过3.2的设备(iPad)在 iTunes 中查看文件,NSLibraryDirectory 常量从 iPhoneOS 2.0开始就可以使用,因此可以用于针对3.0的构建(如果你仍在这样做,甚至更早)。此外,用户将无法看到任何东西,除非你标记一个应用程序,允许用户修改文档,所以如果你正在使用文档,只要你改变位置时,更新用户文档的支持。

最后有一个缓存目录,在那里你可以放置你不关心长期存在或不存在的图像(手机可能会在某个时候删除它们) :

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachePath = [paths objectAtIndex:0];
BOOL isDir = NO;
NSError *error;
if (! [[NSFileManager defaultManager] fileExistsAtPath:cachePath isDirectory:&isDir] && isDir == NO) {
[[NSFileManager defaultManager] createDirectoryAtPath:cachePath withIntermediateDirectories:NO attributes:nil error:&error];
}

注意,您必须在那里实际创建 Cache 目录,因此在编写时您必须每次都检查并创建!有点痛,但就是这样。

然后当你有一个可写的路径时,你只需要像这样附加一个文件名:

NSString *filePath =  [documentsDirectory stringByAppendingPathComponent:@"SomeDirectory/SomeFile.txt"];

或者

NSString *filePath =  [cachePath stringByAppendingPathComponent:@"SomeTmpFile.png"];

使用该路径进行阅读或写作。

请注意,您可以在这两个可写路径中的任何一个中创建子目录,上面的示例字符串中有一个正在使用(假设已经创建了一个)。

如果您试图将图像写入照片库,则不能使用文件系统调用来完成此任务-相反,您必须在内存中有一个 UIImage,并使用 UIKit 定义的 UIImageWriteToSavedPhotosAlbum()函数调用。您无法控制目标格式或压缩级别,也不能以这种方式附加任何 EXIF。

感谢上文提到的肯德尔和戴夫,我认为这个修正案很有用。在使用一次性调试代码时,我使用了 Mike Ash 的 NSBlog中的 这个把戏来消除临时变量 isDir & error,最小化代码行数,使冗长度几乎可以忍受:

NSFileHandle *dumpFileHandle = nil;
#ifdef DEBUG
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
if (![[NSFileManager defaultManager] fileExistsAtPath:cachePath isDirectory:&(BOOL){0}])
[[NSFileManager defaultManager] createDirectoryAtPath:cachePath withIntermediateDirectories:YES attributes:nil error:&(NSError*){nil}];
NSString *dumpPath = [cachePath stringByAppendingPathComponent:@"dump.txt"];
[[NSFileManager defaultManager] createFileAtPath:dumpPath contents:nil attributes:nil];
[(dumpFileHandle = [NSFileHandle fileHandleForWritingAtPath:dumpPath]) truncateFileAtOffset:0];
#endif


if (dumpFileHandle) [dumpFileHandle writeData:blah];