iOS学习35数据处理之文件读写
1. 沙盒机制
1> 沙盒概述
每一个iOS应用程序都会为自己创建一个文件系统目录(文件夹), 这个独立、封闭、安全的空间,叫做沙盒
注:① 每一个应用程序都会拥有一个应用程序沙盒
② 应用程序沙盒就是一个文件系统目录
2> 沙盒机制
-
iOS中沙盒机制是一种安全体系
-
它规定了应用程序只能在为该应用程序创建的文件夹(沙盒)内访问文件,不可以访问其他沙盒内的内容(iOS8 已经部分开放访问)
-
所有的非代码文件都保存在这个地方,比如图片、声音、属性列表(plist)、sqlite数据库和文本文件等
3> 沙盒机制的特点
-
独立:每个应用程序都有自己的沙盒,这个沙盒文件只能自己使用
-
封闭:两个应用程序一般只能使用自己的沙盒文件(在iOS8.0之后可以访问跨应用之间沙盒的部分文件)
-
安全:每个沙盒的内容,如果进行修改必须进行授权
4> 沙盒文件系统目录
获取某个模拟器下某个应用程序沙盒的所在位置
/Users/zhaoce/Library/Developer/CoreSimulator/Devices/50E5495D-9216-4AFC-AB15-F60B759BB0C7/data/Containers/Data/Application/22942FA1-AF88-4E44-9200-B2635EC479F7
注:红色字体的路径表示设备(模拟器)的路径
紫色字体的路径表示应用程序沙盒的路径
5> 文件夹查找某个应用程序的沙盒
沙盒文件夹查找的两种方式:
- 第一种方式:
点击[前往] => 同时按住Alt键 => 选中[资源库] => 选中Developer文件夹 => CoreSimulator => Devices => 50E5495D-9216-4AFC-AB15-F60B759BB0C7 => data => Containers => Data => Application => 22942FA1-AF88-4E44-9200-B2635EC479F7 =>=>=>=>=>=>
- 第二种方式:
首先设置显示Mac隐藏文件的命令 defaults write com.apple.finder AppleShowAllFiles -bool true
通过文件的目录一级一级的查找
6> 应用程序的沙盒目录
- Documents:
存储永远不会被删除的文件,他会被iTunes同步,会备份到电脑上,如果需要可以从电脑中取出(在这个文件夹中不能存储一些过大的文件:如视频,音频,图片) 在程序退出的时候不会被删除,但是会被同步
- Library:
① Caches(缓存):这个文件夹的作用主要是用来缓存一些像视频,音频,图片这样的内容(SDWebImage缓存的图片就存在这个文件夹中) 在程序退出的时候不会被删除,也不会被同步
② Preferences(偏好):保存应用程序的偏好设置,iTunes会自动备份这个目录,一般会使用NSUserDefault来取
- tmp:
临时文件夹用来存取临时数据,临时数据是说删除就删除,在程序重启时,数据都会被删除,不会被备份
7> 代码获取目录
- 第一种打开应用程序沙盒路径的方式(直接通过文件夹对应的枚举值取到):
1 // 地址是一个字符串 2 // 第一个参数:枚举值,枚举你具体要查找的文件夹(要进入那个文件夹就直接修改其枚举值即可) NSDocumentDirectory: 进入Document文件夹 3 // 第二个参数: NSUserDomainMask表示用户的主目录 4 // 第三个参数: 一般为YES,表示展示完整的路径 5 // NSSearchPathForDirectoriesInDomains 查找沙盒路径的,返回值是一个数组,这个数组里面只有一个元素,这个元素就是路径,直接用下标取出即可 6 7 // 获取Documents文件夹的路径 8 NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 9 10 NSLog(@"documentPath = %@", documentPath); 11 12 // 获取Caches文件夹的路径 13 NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 14 15 NSLog(@"cachesPath = %@", cachesPath);
- 第二种打开应用程序沙盒路径的方式(先得到主目录文件夹,在通过拼字符串的方式取得):
1 // 第一步:找到主目录文件夹 2 NSString *homePath = NSHomeDirectory(); 3 4 NSLog(@"%@", homePath); 5 6 // 第二步:然后拼接自己想进入的文件夹名称 7 NSString *documentPathTwo = [homePath stringByAppendingPathComponent:@"Documents"]; 8 NSLog(@"%@", documentPathTwo); 9 10 NSString *libraryPath = [homePath stringByAppendingPathComponent:@"Library"]; 11 NSLog(@"%@", libraryPath); 12 13 NSString *cachesPathTwo = [homePath stringByAppendingPathComponent:@"Library/Caches"]; 14 NSLog(@"%@", cachesPathTwo);
特殊文件夹(临时文件夹tmp)的查找方式
1 NSString *tmpPath = NSTemporaryDirectory(); 2 3 NSLog(@"%@", tmpPath);
2. 简单对象的写入与读取
1> 简单对象
iOS中提供4种类型可以直接进行文件存取:
NSString(字符串)
NSArray(数组)
NSDictionary(字典)
NSData(数据)
2> 简单对象的写入/读取
注意:数组(可变与不可变)和字典(可变与不可变)中元素对象的类型,也必须是上述四种,否则不能直接写入文件
3> 将NSString类型的数据类型存储在本地并读取
1 // 1. 需要知道这个对象存在哪里,所有需要一个文件夹路径 2 // 找到Documents文件夹路径 3 NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 4 5 // 2. 我们知道要存储什么?所以需要创建什么 6 // 创建要存储的内容:字符串 7 NSString *str = @"AJAR"; 8 9 // 3. 需要知道字符串最终存放的地方,所以需要创建一个路径去存储字符串 10 NSString *strPath = [documentPath stringByAppendingPathComponent:@"zf.txt"]; 11 12 NSLog(@"%@", strPath); 13 14 // 4. 将字符串写入文件 15 // 第一个参数:写入的文件的路径 16 // 第二个参数:在断电的情况下,会不会自动保存 17 // 第三个参数:编码格式 18 // 第四个参数:错误信息 19 [str writeToFile:strPath atomically:YES encoding:NSUTF8StringEncoding error:nil]; 20 // 将字符串取出 21 // stringWithContentsOfFile这个方法将其取出 22 // 第一个参数:文件的路径 23 // 第二个参数:编码格式 24 // 第三个参数:错误信息 25 NSString *newStr = [NSString stringWithContentsOfFile:strPath encoding:NSUTF8StringEncoding error:nil]; 26 27 NSLog(@"%@", newStr);
4> 将NSArray类型的数据类型存储在本地并读取
1 // 1. 找到Documents文件夹 2 NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 3 4 // 2. 创建一个数组 5 NSArray *array = @[@"Black", @"MBBoy", @"Bpy", @"Spy",@"SeaRoot", @"BoomSky"]; 6 7 // 3. 创建数组存储的最终路径 8 NSString *arrayPath = [documentPath stringByAppendingPathComponent:@"zf.plist"]; 9 10 // 4. 将数组写入到文件中 11 [array writeToFile:arrayPath atomically:YES]; 12 13 NSLog(@"%@", arrayPath); 14 15 // 从文件中取出内容 16 NSArray *newArray = [NSArray arrayWithContentsOfFile:arrayPath]; 17 18 NSLog(@"%@", newArray);
5> 将NSString类型的数据类型存储在本地并读取
1 NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 2 3 NSDictionary *dict = @{ 4 @"name" : @"zf", 5 @"gender" : @"man", 6 @"age" : @24, 7 @"hobby" : @"running" 8 }; 9 10 NSString *dictPath = [documentPath stringByAppendingPathComponent:@"zf.plist"]; 11 12 NSLog(@"%@", dictPath); 13 14 [dict writeToFile:dictPath atomically:YES]; 15 16 NSDictionary *newDict = [NSDictionary dictionaryWithContentsOfFile:dictPath]; 17 18 NSLog(@"%@", newDict);
6> 将NSData类型的数据类型存储在本地并读取(以图片为例)
1 UIImage *image = [UIImage imageNamed:@"v_red_heart_selected"]; 2 3 // 将image类型的对象转换成NSData类型的数据进行存储 4 // 使用UIImageJPEGRepresentation将图片转换成NSData类型的 5 // 第一个参数:要转换的image对象 6 // 第二个参数:表示图片压缩的值 7 // iPhone中将大于2M的图片自动旋转90°进行压缩处理,最终会将图片保存为JPEG格式的 8 NSData *imageData = UIImageJPEGRepresentation(image, 1); 9 10 // 找到路径进行存储 11 NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 12 13 // 最终路径 14 NSString *imagePath = [documentPath stringByAppendingPathComponent:@"123.jpeg"]; 15 16 [imageData writeToFile:imagePath atomically:YES]; 17 18 NSLog(@"%@", imagePath); 19 20 // 读取NSData类型的数据 21 NSData *newData = [NSData dataWithContentsOfFile:imagePath]; 22 23 UIImage *showImage = [[UIImage alloc] initWithData:newData]; 24 25 UIImageView *myImageView = [[UIImageView alloc] initWithImage:showImage]; 26 27 [self.view addSubview:myImageView];
3. 复杂对象的写入和读取
1> 概述
在Foundation框架中不存在的数据类,如:自定义Person类,这些对象无法再程序内通过writeToFile:这个方法写入到文件内
2> 归档与反归档(解挡)
- 如何将复杂对象写入文件
复杂对象无法通过writeToFile:方法进行数据持久化,只能通过复杂对象转换为NSData(这个步骤就是归档),然后在通过writeToFile:写入文件
- 如何从文件中读取复杂对象
从文件中读取NSData数据,将NSData转化为复杂对象(这个步骤就是反归档)
3> 如何进行归档和反归档
首先,复杂对象所属的类要遵守<NSCoding>协议
其次,实现协议中的两个方法:
- (void)encodeWithCoder:(NSCoder *)aCoder; 序列化
- (instancetype)initWithCoder:(NSCoder *)aDecoder; 反序列化
代码:
Person.h
1 #import <Foundation/Foundation.h> 2 3 @interface Person : NSObject <NSCoding> 4 5 // 属性声明 6 /// 姓名 7 @property (nonatomic, copy) NSString *name; 8 9 /// 性别 10 @property (nonatomic, copy) NSString *gender; 11 12 /// 年龄 13 @property (nonatomic, assign) NSInteger age; 14 15 // 语义设置一些内容(15种) 16 17 @end
Person.m
1 #import "Person.h" 2 3 @implementation Person 4 5 // 归档, 将所有的属性进行归档 6 - (void)encodeWithCoder:(NSCoder *)aCoder 7 { 8 [aCoder encodeObject:self.name forKey:@"name"]; 9 [aCoder encodeObject:self.gender forKey:@"gender"]; 10 [aCoder encodeInteger:self.age forKey:@"age"]; 11 NSLog(@"%s", __func__); 12 } 13 14 // 解挡(反归档) 15 - (instancetype)initWithCoder:(NSCoder *)aDecoder 16 { 17 self = [super init]; 18 if (self) { 19 self.name = [aDecoder decodeObjectForKey:@"name"]; 20 self.gender = [aDecoder decodeObjectForKey:@"gender"]; 21 self.age = [aDecoder decodeIntegerForKey:@"age"]; 22 } 23 NSLog(@"%s", __func__); 24 return self; 25 }
4> 归档
1 // 1. 找到document文件夹的目录 2 NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 3 4 // 2. 创建Person对象 5 Person *person = [Person new]; 6 7 person.name = @"zf"; 8 person.gender = @"man"; 9 person.age = 24; 10 11 // 3. 把这个复杂对象归档 12 13 // 3.1 创建NSMutableData,用于c初始化归档工具 14 NSMutableData *data = [NSMutableData data]; 15 16 NSLog(@"data = %@, %d", data, __LINE__); 17 18 // 3.2 创建归档工具 19 NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; 20 21 // 3.3 对要归档的Person对象进行归档 22 [archiver encodeObject:person forKey:@"person"]; 23 24 // 3.4 结束归档 25 [archiver finishEncoding]; 26 27 NSLog(@"data = %@, %d", data, __LINE__); 28 29 // 4. 将归档的内容NSMutableData存储到本地 30 NSString *personPath = [documentPath stringByAppendingPathComponent:@"person.plist"]; 31 32 // 5. 写入 33 [data writeToFile:personPath atomically:YES]; 34 35 NSLog(@"%@", personPath);
5> 反归档(解挡)
1 // 1. 将要解挡的数据取出 2 NSData *resultData = [NSData dataWithContentsOfFile:personPath]; 3 4 // 2. 创建解挡工具 5 NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:resultData]; 6 7 // 3. 对Person对象进行解挡[要使用对象接收] 8 Person *newPerson = [unarchiver decodeObjectForKey:@"person"]; 9 10 // 4. 结束解挡 11 [unarchiver finishDecoding]; 12 13 NSLog(@"name = %@", newPerson.name);