iOS - 沙盒机制

日常使用苹果的APP的时候,我们保存的数据大都保存在哪里呢?
通常情况下,我们的数据多数保存在一个叫沙盒的结构中。所以了解苹果的沙盒存储机制是了解苹果数据存储的第一道门。

一、概述:
  1. 介绍:应用沙盒机制:每个iOS应用都有自己的应用沙盒(文件系统目录),与其他文件系统隔离。每个应用必须在自己的沙盒里运行,其他应用不能访问该沙盒。
  2. 特点:
  • 每个应用程序的活动范围都限定在自己的沙盒里。
  • 不能随意跨越自己的沙盒去访问别的应用程序沙盒中的内容。
  • 在访问别人沙盒内的数据时需要访问权限。
二、沙盒结构介绍:
  • 获取 软件的沙盒路径:
    • 通过NSHomeDirectory()获取沙盒路径并输出:
    NSLog(@"%@",NSHomeDirectory());
    
    • 通过NSSearchPathForDirectoriesInDomains()方法去查找路径:
      NSSearchPathForDirectoriesInDomains的参数说明:
      directory :表示需要查找的是哪一个文件夹,是一个枚举
      domainMask:搜索范围,是一个枚举类型;关于domainMask 看:NSSearchPathDomainMask详解
      expandTilde:是否扩展路径,YES->获取完整路径,一般为YES
      return:返回值为数组,这个数组中只有一个NSString类型元素,一般这个元素保存的就是查找的路径的唯一路径,所以直接取第一个就行了

一般的沙盒的的根目录有三个文件夹,分别是:DocumentsLibrarytmp

  • Documents/:
    Documents一般用来保存APP中需要持久保存的文件和数据,例如游戏进度,绘图软件的绘图等,当iTunes 连接的时候会去备份和恢复Documents文件夹数据

⚠️注意:在此目录下不要保存从网络上下载的文件,否则app无法上架!

获取 Documents/ 文件的路径:

NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
  • Library/:
    Library目录下有两个子目录:Caches 和 Preferences
    获取 Library/ 的路径:
NSString *path = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES).lastObject;
  • Library/Caches:
    顾名思义,用来保存数据中的一些缓存的持久化数据,这些数据一般是体积较大,但并不是绝对需要的数据(多为网络请求的数据,如图片和视频等),这些数据需要用户自己去管理删除,当iTunes 连接的时候不会去备份和恢复数据
    获取 Library/Caches 路径
 NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject;
  • Library/Preferences:
    Preferences翻译过来就是偏好、偏爱的意思,所以多用来保存软件一些偏好设置(setting)当iTunes 连接的时候会去备份和恢复 Library/Preferences文件夹数据
    获取Library/Preferences的路径:
NSString *path = NSSearchPathForDirectoriesInDomains(NSPreferencePanesDirectory, NSUserDomainMask, YES).lastObject;
  • tmp/:
    此目录保存应用程序运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份 tmp 目录
    获取 tmp/ 文件夹路径:
NSString *path = NSTemporaryDirectory();
三、文件操作
  1. 创建文件夹/目录
    通过 createDirectoryAtPath 方法实现:
- (BOOL)createDirectoryAtPath:(NSString *)path withIntermediateDirectories:(BOOL)createIntermediates attributes:(nullable NSDictionary *)attributes error:(NSError **)error;

参数说明:
path:文件夹/目录的路径
withIntermediateDirectories:中间目录,如果为createIntermediates传递'NO',则在进行此调用时目录不能存在。为“createIntermediates”传递“YES”将创建任何必要的中间目录。如果创建了“path”中指定的所有目录并设置了属性,则此方法返回YES。,一般返回YES
attributes:目录是用传递给“attributes”的字典指定的属性创建的。如果没有提供字典,则根据进程的umask创建目录。具体设置查看文章
(Objective-C创建目录接口)[https://blog.csdn.net/wanganqi19920813/article/details/8849706]
error:如果提供了错误参数,则会通过引用返回可呈现的NSError
return:如果在操作的任何阶段发生故障,则此方法返回NO

-(BOOL)createDir:(NSString *)fileName{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);  
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString * path = [NSString stringWithFormat:@"%@/%@",documentsDirectory,fileName];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    BOOL isDir;
    if  (![fileManager fileExistsAtPath:path isDirectory:&isDir]) {//先判断目录是否存在,不存在才创建
    BOOL res=[fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil]; 
    return res;  
 } else return NO; 
  1. 创建文件
    通过 createFileAtPath:方法实现
- (BOOL)createFileAtPath:(NSString *)path contents:(nullable NSData *)data attributes:(nullable NSDictionary *)attr

参数介绍:
path:用来指定要创建的文件
data:用来指定文件中的数据
attr:用来指定字典,一般设置为nil
return:返回创建的结果
当(NSData *)data和(NSDictionary *)attr都设置为nil时,创建出来的文件就是一个空文件。

-(BOOL)createFile:(NSString *)path{  
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *testPath = [path stringByAppendingPathComponent:@"test.c"];//在传入的路径下创建test.c文件
    //通过data创建数据
    NSData *data=[@"Hello world" dataUsingEncoding:NSUTF8StringEncoding];
    BOOL res = [fileManager createFileAtPath:testPath contents:data attributes:nil];
    return res; 
}  
  1. 写数据到文件
    通过 writeToFile: 方法实现
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile encoding:(NSStringEncoding)enc error:(NSError **)error

参数说明:
path:存储的文件夹路径
atomically:如果为YES则保证文件的写入原子性,就是说会先创建一个临时文件,直到文件内容写入成功再导入到目标文件里,如果为NO,则直接写入目标文件里
encoding:格式
error:错误信息
return:写入是否正确

  1. 读数据
    通过 stringWithContentsOfFile: 或者 initWithContentsOfFile: 方法实现
    参数和写入的差不多
-(void)readFile:(NSString *)path{  
//方法1:
    NSData * data = [NSData dataWithContentsOfFile:path];  
    NSString * content = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);  
//方法2:    
    NSString * content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];  
    NSLog(@"文件读取成功: %@",content);  
}  
  1. 查看是否有相关文件
    通过方法 isExecutableFileAtPath:
- (BOOL)isExecutableFileAtPath:(NSString *)path
  1. 获取文件的属性:
-(void)fileAttriutes:(NSString *)path{  
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:path error:nil];     
    NSArray *keys;  
    id key, value;  
    keys = [fileAttributes allKeys];  
    int count = [keys count];  
    for (int i = 0; i < count; i++)  
    {  
        key = [keys objectAtIndex: i];  //获取文件名
        value = [fileAttributes objectForKey: key];  //获取文件属性
    }  
}  
  1. 根据路径删除文件
    通过方法 removeItemAtPath:
-(BOOL)deleteFileByPath:(NSString *)path{  
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    BOOL res=[fileManager removeItemAtPath:path error:nil];  
    return res;      
}  
  1. 根据文件名删除文件
- (BOOL)deleteFileByName:(NSString *)name{
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    [fileManager removeItemAtPath:[self getLocalFilePath:fileName] error:nil];//getLocalFilePath方法在下面
}
  1. 复制文件
    通过 copyItemAtPath: 方法实现
+(BOOL)copyFile:(NSString *)path topath:(NSString *)topath
{
    
    BOOL result = NO;
    NSError * error = nil;
    
    result = [[NSFileManager defaultManager]copyItemAtPath:path toPath:topath error:&error ];
    
    if (error){
        NSLog(@"copy失败:%@",[error localizedDescription]);
    }
    return result;
}
  1. 根据文件名获取文件路径
  • 资源文件
+(NSString *)getResourcesFile:(NSString *)fileName
{
    return [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
}
  • 普通文件
+(NSString *)getLocalFilePath:(NSString *) fileName
{
    NSString * path = [NSHomeDirectory() stringByAppendingPathComponent:@"/Documents"]
    return [NSString stringWithFormat:@"%@/%@",path,fileName];
}
  1. 根据文件路径获取文件名称
+(NSString *)getFileNameByPath:(NSString *)filepath
{
    NSArray *array=[filepath componentsSeparatedByString:@"/"];
    if (array.count==0) return filepath;
    return [array objectAtIndex:array.count-1];
}
  1. 根据路径获取该路径下所有目录
+(NSArray *)getAllFileByName:(NSString *)path
{
    NSFileManager *defaultManager = [NSFileManager defaultManager];
    NSArray *array = [defaultManager contentsOfDirectoryAtPath:path error:nil];
    return array;
}
  1. 根据路径获取文件目录下所有文件
+(NSArray *)getAllFloderByName:(NSString *)path
{
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    NSArray * fileAndFloderArr = [self getAllFileByName:path];
    
    NSMutableArray *dirArray = [[NSMutableArray alloc] init];
    BOOL isDir = NO;
    //在上面那段程序中获得的fileList中列出文件夹名
    for (NSString * file in fileAndFloderArr){
        
        NSString *paths = [path stringByAppendingPathComponent:file];
        [fileManager fileExistsAtPath:paths isDirectory:(&isDir)];
        if (isDir) {
            [dirArray addObject:file];
        }
        isDir = NO;
    }
    return dirArray;
}

14.获取文件及目录的大小

+(float)sizeOfDirectory:(NSString *)dir{
    NSDirectoryEnumerator *direnum = [[NSFileManager defaultManager] enumeratorAtPath:dir];
    NSString *pname;
    int64_t s=0;
    while (pname = [direnum nextObject]){
        //NSLog(@"pname   %@",pname);
        NSDictionary *currentdict=[direnum fileAttributes];
        NSString *filesize=[NSString stringWithFormat:@"%@",[currentdict objectForKey:NSFileSize]];
        NSString *filetype=[currentdict objectForKey:NSFileType];
        
        if([filetype isEqualToString:NSFileTypeDirectory]) continue;
        s=s+[filesize longLongValue];
    }
    return s*1.0;
}
  1. 重命名文件或者目录
+(BOOL)renameFileName:(NSString *)oldName toNewName:(NSString *)newName
{
    
    BOOL result = NO;
    NSError * error = nil;
    result = [[NSFileManager defaultManager] moveItemAtPath:[kDSRoot stringByAppendingPathComponent:oldName] toPath:[kDSRoot stringByAppendingPathComponent:newName] error:&error];
    
    if (error){
        NSLog(@"重命名失败:%@",[error localizedDescription]);
    }
    
    return result;
}
  1. 读取文件
+(NSData *)readFileContent:(NSString *)filePath{
    
    return [[NSFileManager defaultManager] contentsAtPath:filePath];
}
  1. 保存文件
+(BOOL)saveToDirectory:(NSString *)path data:(NSData *)data name:(NSString *)newName

{
    NSString * resultPath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"/%@",newName]];
    return [[NSFileManager defaultManager] createFileAtPath:resultPath contents:data attributes:nil];
}

沙盒的介绍就到这里,如果喜欢不妨点个赞,如有错误或者疑问欢迎评论区留言,一起加油⛽️
参考文章:
iOS 开发之沙盒机制
iOS之NSFilemanager文件管理(沙盒)

你可能感兴趣的:(iOS - 沙盒机制)