一,沙盒

iOS 中的沙盒机制(SandBox)是一种安全体系。

每个 iOS 应用程序都有一个单独的文件系统(存储空间),而且只能在对应的文件系统中进行操作,此区域被称为沙盒。所有的非代码文件都要保存在此,例如属性文件 plist、文本文件、图像、图标、媒体资源等。

Application:存放程序源文件,上架前经过数字签名,上架后不可修改,由于应用程序必须经过签名,所以不能在运行时对这个目录中的内容进行修改,否则会导致应用程序无法启动。

每个应用沙盒含有3个文件夹:Documents, Library 和 tmp

iOS中writeToFile存储图片 ios文件存储机制_ios


1,Documents:常用目录,iCloud备份目录,存放数据,这里不能存缓存文件,否则上架不被通过,保存应用程序的重要数据文件和用户数据文件等。iTunes 同步时会备份该目录

2,Library:

&Caches:保存应用程序使用时产生的支持文件和缓存文件,还有日志文件最好也放在这个目录。iTunes 同步时不会备份该目录。比如下载的音乐,视频,SDWebImage缓存等

&Preference:设置目录,iCloud会备份设置信息

3,tmp:存放临时文件,不会被备份,而且这个文件下的数据有可能随时被清除的可能,按照官方说法每三天清理一次缓存数据.

对于上述描述可以这样举例理解,一个记事本应用,用户写的东西需要保存起来,这些东西是用户自行生成的,则需要放在 Documents 目录里。一个新闻应用,如果需要从服务器下载东西展示给用户看,下载的东西就放在 Library/Caches 目录里。苹果审核对这个要求很严格,主要原因是 iCloud 的同步问题。

(1).获取沙盒文件对应的存储路径

//沙盒的根路径
    NSString *rootPath = NSHomeDirectory();
    //获取Documents目录
    //[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];

    //获取Library路径
    //[NSHomeDirectory() stringByAppendingPathComponent:@"Library"];
    NSArray *libPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
    NSString *libraryDirectory = [libPaths objectAtIndex:0];

    //获取Library路径下的catch 路径
    NSArray *cacPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);

    NSString *cachePath = [cacPath objectAtIndex:0];

    //[NSHomeDirectory() stringByAppendingPathComponent:@"tmp"];
    NSString *tmp = NSTemporaryDirectory();
    //拼接路径
     NSString *tempFilePath = [tmp stringByAppendingPathComponent:@".File"];
   }

(2).使用NSFileManager操作文件

NSString *mypath  = @"你要操作的文件路径";
    //拼接路径
    NSString *doctorPath = [mypath stringByAppendingPathComponent:@"test"];
    //创建文件管理器对象
    NSFileManager *manager = [NSFileManager defaultManager];
    //创建文件夹
    NSError *error = nil;
   BOOL iscreateSuccess = [manager createDirectoryAtPath:doctorPath withIntermediateDirectories:YES attributes:nil error:&error];

    //创建文件
    NSString *filePath = [doctorPath stringByAppendingPathComponent:@"test.txt"];
    NSData *filecontent = [@"hello world" dataUsingEncoding:NSUTF8StringEncoding];
    BOOL iscreateFileOk = [manager createFileAtPath:filePath contents:filecontent attributes:nil];

    //写入数据到文件
   BOOL isWriteOk = [@"mydata for me" writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];

    //读取数据
   //1 NSData *data = [NSData dataWithContentsOfFile:filePath];
  NString datacontent =  [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];

    //删除文件
  BOOL isDeleteOk = [manager removeItemAtPath:filePath error:nil];

二,使用 plist存储

特点:(1)只能存储OC常用数据类型(NSString、NSDictionary、NSArray、NSData、NSNumber等类型)而不能直接存储自定义模型对象
(2).如果想存储自定义模型对象 -> 只能将自定义模型对象转换为字典存储;
(3).使用前提条件:一个对象必须实现了writeToFile方法,因为我们是通过调用对象的writeToFile方法将对象写入到一个plist文件中的
(4). plist只能识别字典,数组

获取文件路径,同上沙盒路径

//文件存储的位置(同上)
 +(NSString*)getFilePath{
    NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
    //拼接要保存的路径
    NSString *filePath = [path stringByAppendingPathComponent:FILEPATH];
    return filePath ;
}

写入要存储的数据

+(void)writeToFile:(id)data{
    if ([data isKindOfClass:[NSDictionary class]]) {
        NSDictionary *dicdata = (NSDictionary *)data ;
        [dicdata writeToFile:[MyPlist getFilePath] atomically:YES];
    }else if([data isKindOfClass:[NSArray class]]){
        NSArray *arrdata = (NSArray*)data ;
        [arrdata writeToFile:[MyPlist getFilePath] atomically:YES];
    }else{
        NSLog(@"error");
    }

}

读取plist文件数据

+(id)readFromFile{
    Boolean isdictionary = YES ;
    if(isdictionary){
        NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:[MyPlist getFilePath]];
        return dic ;
    }else{
        NSArray *array = [NSArray arrayWithContentsOfFile:[MyPlist getFilePath]];
        return array ;
    }

}

三,归档 NSKeyedArchiver

这个有点像java序列化serializable
特点:
(1).可以存储自定义模型对象
NSKeyedArchiver归档相对较plist存储而言,它可以直接存储自定义模型对象,而plist文件需要将模型转为字典才可以存储自定义对象模型;
(2).归档不能存储大批量数据(相比较Sqlite而言),存储数据到文件是将所有的数据一下子存储到文件中,从文件中读取数据也是一下子读取所有的数据;
缺点:
(3).假如你的文件中有多个对象,然后你想在利用归档添加一个对象,你需要先把所有的数据解档出来,然后再加入你想添加的那个对象,同理,你想删除一个文件中的一个对象也是,需要解档出所有的对象,然后将其删除。这样处理性能低下
(4).关于使用:需要归档的模型类必须要遵守NSCoding协议,然后模型实现类中必须实现两个方法:1>encodeWithCoder -> 归档;2> initWithCoder: - > 解档

(5). 使用注意:

如果父类也遵守了NSCoding协议,请注意:

应该在encodeWithCoder:方法中加上一句

[super encodeWithCode:encode]; 
// 确保继承的实例变量也能被编码,即也能被归档

应该在initWithCoder:方法中加上一句

self = [super initWithCoder:decoder]; 
// 确保继承的实例变量也能被解码,即也能被恢复
// 1. 自定义模型类Person

// 1.1 Person.h文件
#import <Foundation/Foundation.h>

// 只要一个自定义对象想要归档,必须要遵守NSCoding协议,并且要实现协议的方法
@interface Person : NSObject<NSCoding>

@property (nonatomic, assign) int age;

@property (nonatomic, strong) NSString *name;

@end

// 1.2 .m实现文件
#import "Person.h"

#define KName @"name"
#define KAge @"age"

@implementation Person

// 什么时候调用:当一个对象要归档的时候就会调用这个方法归档
// 作用:告诉苹果当前对象中哪些属性需要归档
- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject:_name forKey:KName];
    [aCoder encodeInt:_age forKey:KAge];
}

// 什么时候调用:当一个对象要解档的时候就会调用这个方法解档
// 作用:告诉苹果当前对象中哪些属性需要解档
// initWithCoder什么时候调用:只要解析一个文件的时候就会调用
- (id)initWithCoder:(NSCoder *)aDecoder
{
    #warning  [super initWithCoder]
    if (self = [super init]) {
        // 解档
        // 注意一定要记得给成员属性赋值
      _name = [aDecoder decodeObjectForKey:KName];
      _age = [aDecoder decodeIntForKey:KAge];
    }
    return self;
}

@end

// 2. 实例 -基本使用:取 / 存 数据 
// 归档
 [NSKeyedArchiver archiveRootObject: self.persons toFile:KFilePath];// 将self.persons模型对象数组 

 // 解档       
 _persons = [NSKeyedUnarchiver unarchiveObjectWithFile:KFilePath];