iOS

iOS 沙盒与文件管理类

Posted by Matt Reach on August 12, 2017

正常情况下,我们的文档只能存储到沙盒里,在写业务逻辑时经常需要判断沙盒里某个文件是否存在,或者文件夹不存在创建文件夹等操作,因此写篇文章记录下如何获取沙盒路径,如何使用文件管理类创建目录等常用操作。

沙盒路径

什么是沙盒?为了保证App的正常运行,不受到其他App的干扰,或者病毒的侵害,苹果为每个App设定了自己独立的目录,对于开发者而言,你只能访问这个目录下的文件或者子目录,这个目录是你App的根目录,这就是沙盒机制,大大减少了流氓软件和病毒。

关于沙盒设计可看官方介绍 App Sandbox Design Guide

沙盒内重要目录

获取沙盒根目录,直接使用这个 C 方法就OK了:

NSHomeDirectory()

沙盒里面有几个文件夹还记得吗?有 3 个,分别是:

  • Documents : 一般重要的文件会放这里,不过默认情况下,备份App时会备份这里面的数据;这个目录也可以设置共享,就可以在itunes里向App导入数据了

NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)

注意:NSSearchPathForDirectoriesInDomains 函数返回的是个数组,取一个就行了。

  • Library/Caches : 一般会将图片这种没那么重要的资源缓存到这里

NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)

  • tmp : 就是个临时目录,中间临时文件,存这里面,系统可能会删这里的文件,最好我们自己清理临时文件,减少沙盒的体积

NSTemporaryDirectory()

这三个都在App沙盒根目录里,因此也可以通过 NSHomeDirectory() 拼接出来。

管理文件和目录

iOS 里使用 NSFileManager 类管理文件(夹),这是一个单利类,但你仍旧可以创建新的实例,自己使用。下面总结下 NSFileManager 的常用方法:

  • 创建文件
1
2
3
4
5
6
7
8
NSFileManager *fileManager = [NSFileManager defaultManager];
///文件路径,文件内容,相关属性
BOOL succ = [fileManager createFileAtPath:path contents:nil attributes:nil];
if (succ) {
    NSLog(@"创建成功");
} else {
    NSLog(@"创建失败");
}
  • 直接写入文件

NSString,NSData,NSArray,NSDictionary等常用类均提供了直接写入文件的方法;这里以 NSString 举例说明;由于这个方法的存在,所以上面的创建文件方法用的不是很多;

1
2
3
4
5
6
7
8
NSString *iOSPath = [documentsPath stringByAppendingPathComponent:@"iOS.txt"];
NSString *text = @"测试直接写入";
BOOL succ = [text writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
if (succ) {
    NSLog(@"写入成功");
} else {
    succ(@"写入失败");
}
  • 从文件读取
1
2
3
4
- (void)readFileContent{
    NSString *text = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
    NSLog(@"text: %@", text);
}
  • 创建文件夹
1
2
3
4
5
6
7
8
NSFileManager *fileManager = [NSFileManager defaultManager];
///第二个参数,一般传YES,意思是创建中间目录;
BOOL succ = [fileManager createDirectoryAtPath:@"/a/b/c" withIntermediateDirectories:YES attributes:nil error:nil];
if (succ) {
    NSLog(@"创建成功");
} else {
    NSLog(@"创建失败");
}
  • 删除文件,文件夹

最好在异步线程里删除文件

1
2
3
4
5
6
7
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL succ = [fileManager removeItemAtPath:path error:nil];
if (succ) {
    NSLog(@"删除成功");
}else{
    NSLog(@"删除失败");
}
  • 文件是否存在
1
2
3
4
5
6
BOOL succ = [[NSFileManager defaultManager]fileExistsAtPath:savePath];
if (succ) {
    NSLog(@"文件存在");
}else{
    NSLog(@"文件不存在");
}
  • 文件夹是否存在
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
NSString *basePath = [cachePath stringByAppendingPathComponent:@"telittleVideo"];
    
BOOL directory = NO;
///注意,文件夹存在时,这个方法返回的也是YES哦,所以要继续判断 directory !
if ([[NSFileManager defaultManager]fileExistsAtPath:basePath isDirectory:&directory] && !directory) {
	 ///如果不是文件夹,那么说明存在了同名文件了,删掉吧
    [[NSFileManager defaultManager]removeItemAtPath:basePath error:nil];
}
    
///文件夹不存在,要创建
if(!directory){
    NSError *err = nil;
    [[NSFileManager defaultManager] createDirectoryAtPath:basePath withIntermediateDirectories:YES attributes:nil error:&err];
    NSLog(@"%@",err);
}