第一章 Senior进阶 数据处理之文件读写
一、沙盒机制
1.沙盒(SandBox):每一个iOS应用程序都会为自己创建一个文件系统目录(文件夹),这个独立、封闭、安全的空间,叫做沙盒,十六进制的文件夹,应用程序没运行一次,这个文件夹的名称就会变换
注:1.每一个应用程序都会拥有一个应用程序沙盒
2.应用程序沙盒就是一个文件系统目录
2.沙盒机制:
1.沙盒是一种安全体系
2.它规定了应用程序只能在为该应用程序创建的文件夹(沙盒)内访问文件,不可以访问其他沙盒内的内容(iOS8 已经部分开放访问,比如日历)。
3.所有的非代码文件都保存在这个地方,比如图片、声音、属性列表(plist)、SQlite数据库和文本文件等。
3.沙盒机制的特点
1.每个应用程序的活动范围都限定在自己的沙盒里
2.不能随意跨越自己的沙盒去访问别的应用程序沙盒中的内容(iOS8 已经部分开放访问)
3.应用程序向外请求或接收数据都需要经过权限认证
4.沙盒文件系统目录
获取某个模拟器下某个应用程序沙盒的所在位置
5.应用程序中的沙盒目录,三个特殊的文件夹
Documents:是用来保存应用运行时生成的需要持久化的数据,iTunes会自动备份该目录,苹果建议将程 序中建立的或在程序中浏览到的文件数据保存在该目录下,iTunes备份和恢复的时候会包括此目录
手动保存的文件在documents文件中
Library:存储程序的默认设置和其他状态信息
1.Library/Caches:存放缓存文件,iTunes不会备份此目录,此目录下文件不会在应用退出时删除。一般存放体积比较大,不是特别重要的资源
2.Library/Preferences:保存应用的所有偏好设置,iOS的Settings(设置)应用会在该目录中查找应用的设置信息,iTunes会自动备份该目录。注意:偏好设置文件不应该直接创建,而是应该使用NSUserDefaults类来取得和设置应用程序的偏好
tmp:用来保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也有可能会清除该目录下的文件,iTunes不会同步该目录。iPhone重启时,该目录下的文件会被删除
NSUserDefault保存的文件在tmp文件夹里(临时的文件)
5.获取沙盒的主路径
NSString* homePathString = NSHomeDirectory();
6.获取Documents目录的路径
第一步:
NSSArray* documentsArray = NSSearchPathForDirectoriesInDomains(NSDocumentsDirectory,NSUserDomainMask,YES);
参数解释:
第一个参数:要找寻的目标文件
第二个参数:查找的范围(要找寻的目标文件夹的父级文件夹)
第三个参数:文件的路径是否展开
注意:调用方法的方式是C语言的方法
第二步:
NSString* documentsPath = documentsArray.firstObject;
7.获取tmp目录的路径
NSString* tmpPath = NSTemporaryDirectory();
8.获取Library目录的路径
NSArray* librarysArray = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
9.获取Library目录下Caches的路径
NSArray* cachesArray = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
10.获取Library目录下Preferences的路径
注意:通常情况下,Preferences由系统维护,所以我们很少去操作它
第一步:
NSString* libraryPath = librarysArray.firstObject;
第二步:NSString* preferences = [libraryPath stringByAppendingString:@"/preferences"];
注意:如果是使用stringByAppendingString的方法进行拼接,字符串前面需加上向左的下划线;如果是使用stringByAppendingPathComponent的方法进行拼接,在字符串前面则不需要添加下划线。
11.获取应用程序包目录和内容的路径()也就是读取左侧目录栏的文件
注意:应用程序中的文件只可读不可写
1.获取应用程序包路径
NSString* imagePath = [NSBundle mainBundle].resourcePath;
2.获取程序包中的一个图片资源(apple.png)路径的方法:
NSString* imagePath = [[NSBundle mainBundle] pathForResource:@"apple" ofType:@"png"];
二、简单对象的写入与读取
1.简单对象:可以直接进行文件存取的类型:
NSString(字符串)
NSArray(数组)
NSDictionary(字典)
NSData(数据):二进制对象可能存储的是图像、字符串等
以上类型包括子类
2.简单对象的写入和读取的方法
NSString/NSMutableString
读取的方法
stringWithContentsOfFile:encoding:error:
写入的方法
writeToFile:atomically:encoding:error:
NSArray/NSMutableArray
读取的方法
arrayWithContentsOfFile:
写入的方法
writeToFile:atomically:
NSDictionary/NSMutableDictionary
读取的方法
dictionaryWithContentsOfFile:
写入的方法
writeToFile:atomically:
NSData/NSMutableData
读取的方法
dataWithContentsOfFile:
写入的方法
writeToFile:atomically:
注意:数组中(可变与不可变)和字典(可变与不可变)中元素对象的类型,也必须是上述四种,否则不能直接写入文件
3.PList文件
全名是Property List,属性列表文件,它是一种用来存储串行化后的对象的文件。属性列表文件的扩展名为.plist,因此通常被称为plist文件。文件是xml格式的
作用:Plist文件通常是用于存储用户设置,也可以用于存储捆绑的信息
4.字符串类型的文件的写入和读取
1.写入
第一步:获取将文件存储的某个文件夹的的路径
NSString* docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
第二步:通过已经获取的文件夹的路径的对象使用拼接的方式创建一个存储文件内容的文件路径,并确定所存储文件的类型
NSString* txtPath = [dicPath stringByAppendingString:@"/string.txt"];
注意:当文字写入文件的时候,如果文件不存在,系统会先创建,在写入;如果存在,直接写入。写的内容会将原有的内容覆盖掉
第三步:创建要存储的文件的内容的对象
NSString* contentString = @"我是文本内容";
第四步:进行写入操作
[contentString writeToFile:txtPath atomically:YES encoding:NSUTF8StringEncoding error:&error];
参数解释:
第一个参数:文件路径
第二个参数:内容属性的原子性,是一个Bool类型的属性
YES 在写入过程中会产生一个临时文件,当内容写入完整的时候,才会将内容移动到目标文件;
NO 直接在目标文件上操作,不产生临时文件,有可能损坏目标文件
第三个参数:字符串的编码格式,常用的格式是:NSUTF8StringEncoding
第四个参数:error 如果写入出问题,这里会产生一个错误日志,一般不需要错误日志,直接赋值为nil
在这里我们可以通过错误日志判断写入是否成功
第一种方式(有写入失败的细节描述)
1.在写入之前创建error对象,并赋值为nil
NSError* error = nil;
2.在写入之后,判断是否写入成功
if (error) {
NSLog(@"写入文件出错 ----- %@",error.description);
}else{
NSLog(@"写入成功");
}
第二种方式(只知道写入的结果,没有失败过程描述)
1.由于写入的方法本身是一个bool类型,所以我们可以通过返回的对象判断是否写入成功
BOOL isSuccess = [contentString writeToFile:txtPath atomically:YES encoding:NSUTF8StringEncoding error:&error];
2.判断是否写入成功
if (isSuccess) {
NSLog(@"成功 ----- %@",txtPath);
}else{
NSLog(@"失败");
}
2.读取
第一步:获取要读取文件所在文件夹的路径
NSString* docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
第二步:获取文件自身的路径
NSString* txtPath = [docPath stringByAppendingPathComponent:@"string.txt"];
第三步:读取文件
NSString* readString = [NSString stringWithContentsOfFile:txtPath encoding:NSUTF8StringEncoding error:nil];
5.将图片写入到文件中
第一步:获取将文件存储的某个文件夹的的路径
NSString* docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
第二步:通过已经获取的文件夹的路径的对象使用拼接的方式创建一个存储文件内容的文件路径,并确定所存储文件的类型
NSString* imagePath = [docPath stringByAppendingPathComponent:@"333.jpg"];
第三步:图片写入
1.将图片转换为NSData类型才能写入文件
UIImage * image = [UIImage imageNamed:@"1.jpg"];
2.UIImage - 》NSData
参数:图片对象,图片的品质
NSData* imageData = UIImageJPEGRepresentation(image, 1.0);
3.将文件写入
[imageData writeToFile:imagePath atomically:YES];
三、文件管理器
1.文件管理器与文件连接器之间的区别
1.文件管理器(NSFileManager):此类主要是对文件进行的操作(创建/删除/改名等)以及文件信息的获取。
2.文件连接器(NSFileHandle):此类主要是对文件内容进行读取和写入操作。
2.文件管理器(NSFileManager)
1.创建文件管理器对象
NSFileManager* fileManager = [NSFileManager defaultManager];单例方法创建
NSFileManager* manager = [[NSFileManager alloc] init];初始化的方式创建
2.创建一个文件并写入数据
第一个参数:要创建文件的路径
第二个参数:要写入文件的内容(NSData类型)
第三个参数:设置文件的用户组、权限、修改时间等设置。如果赋值为nil,系统会自动为文件加一些默认设置
- (Bool)createFileAtPath:(NSString*)path contents:(NSData*)data attributes:(NSDictionary*)dic;
注意:如果该方法的返回值为YES:文件创建成功或者文件已经存在,否则为NO
3.从一个文件中读取数据
- (NSData*)contentsAtPath:(NSString*)path;
4.srcPath路径上的文件移动到dstPath路径上。
注意:这里的路径是文件路径而不是目录
- (Bool)moveItemAtPath:(NSString*)srcPath toPath:(NSString*)dstPath error:(NSError**)error;
5.srcPath路径上的文件复制到dstPath路径上
- (Bool)copyItemAtPath:(NSString*)srcPath toPath:(NSString*)dstPath error:(NSError**)error;
6.比较两个文件的内容是否一样
- (Bool)contentsEqualAtPath:(NSString*)path1 andPath:(NSString*)path2;
7.文件是否存在
- (Bool)fileExistsAtPath:(NSString*)path;
8.移除文件
- (Bool)removeItemAtPath:(NSString*)path error:(NSError**)error;
9.创建文件夹
BOOL isFail = [fileManager createDirectoryAtPath:[[SandBoxPaths homePath] stringByAppendingString:@"/aaa/bbb/ccc"] withIntermediateDirectories:YES attributes:nil error:nil]
参数解释:
第一个参数:要创建的文件夹的路径
第二个参数:YES:如果父目录(文件夹)不存在,创建的时候会将父目录一起创建;No:如果父目录不存在,那么文件夹就会创建失败
第三个参数:文件的权限(一般设置为nil)
第四个参数:错误日志(一般设置为nil)
10.将数组转换为NSData
NSData* arrayData = [NSJSONSerialization dataWithJSONObject:array options:NSJSONWritingPrettyPrinted error:nil];
11.将NSData数据转换为数组
NSArray* readArray = [NSJSONSerialization JSONObjectWithData:readData options:NSJSONReadingAllowFragments error:nil];
3.文件对接器(NSFileHandle)
1.NSFileHandle:是一个非常基础的只针对文件内容的操作(写入、读取、更新),是把NSData,通过连接器一个字节一个字节的写入/读取文件.(NSData <--> NSFileHandle < -- > 文件)
2.使用场景:对文件内容的进行布局修改,追加内容
3.使用步骤:
1.文件对接并获取一个NSFileHandle对象
2.读写操作
3.关闭对接
==注意:NSFileHandle类没有提供创建文件的功能。必须使用NSFileManager方法来创建文件。因此在使用其方法的时候,都是保证文件已经存在,否则返回nil==
if (![fileManager fileExistsAtPath:path]) {
//文件不存在,创建
[fileManager createFileAtPath:path contents:nil attributes:nil];
}
4.文件对接器的处理方法
1.打开一个文件准备读取
+ (id)fileHandleForReadingAtPath:(NSString*)path;
2.打开一个文件准备写入
+ (id)fileHandleForWritingAtPath:(NSString*)path;
3.打开一个文件准备更新
+ (id)fileHandleForUpdatingAtPath:(NSString*)path;
4.从设备或者通道返回可用的数据
- (NSData*)availableData;
5.从当前的节点读取到文件的末尾
- (NSData*)readDataToEndOfFile;
6.从当前节点开始读取指定的长度数据
- (NSData*)readDataOfLength:(NSInteger)length;
7.写入数据
- (void)writeData:(NSData*)data;
8.获取当前文件的偏移量
- (unsigned long long)offsetInFile;
9.跳到指定文件的偏移量
- (void)seekToFileOffset:(unsigned long long)offset;
注意:如果将文件偏移量设置为1,然后写入,相当于是从1位置开始,将后面的内容进行替换
10.跳到文件末尾
- (unsigned long long)seelToEndOfFile;
11.将文件的长度设为offset字节(如果将长度设置为0相当于清除数据)
- (void)truncateFileAtOffset:(unsigned long long)offset;
12.关闭文件,在操作完成之后一定要关闭
- (void)closeFile;
13.将字符串转换为NSData
NSData* inputData = [inputString dataUsingEncoding:NSUTF8StringEncoding];
14.将NSData转换为字符串
NSString* readString = [[NSString alloc] initWithData:readData encoding:NSUTF8StringEncoding];
四、复杂对象的写入与读写
1.复杂对象:在Foundation框架内不存在的数据类,如:自定义的Person类,无法在程序内通过writeToFile:这个方法写入到文件中,为了能让数据写入,我们需要将复杂对象转换为简单对象进行数据写入,也可以将Person转化为字典进行数据写入
2.归档与反归档(序列化和反序列化)
归档:将复杂对象写入文件的过程(复杂对象 --> 归档 --> NSData --> writeToFile)
反归档:从文件中读取复杂对象的过程(读取文件 --> NSData --> 反归档 --> 复杂对象)
3.归档到反归档的过程
1.在Person类的.h文件中遵循协议(NSCoding)
2.声明Person类的属性
3.在Person的.m文件中实现归档(encode)和反归档(init)协议方法,对Person类的属性进行归档和反归档
归档属性:
- (void)encodeWithCoder:(NSCoder *)aCoder{
//归档过程是将当前对象的每一个属性都进行编码
//第一个参数:要进行编码的属性的值
//第二个参数:为属性的值加标记,加标记是为了解码使用
//带星号的
[aCoder encodeObject:self.name forKey:@"name"];
//基本类型
[aCoder encodeInt:self.age forKey:@"age"];
NSLog(@"执行了归档的方法");
}
反归档属性:
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
self = [super init];
if (self) {
//解码 从文件中读取出来的值,赋值给对应的属性
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = [aDecoder decodeIntForKey:@"age"];
}
NSLog(@"执行了反归档的方法");
return self;
}
4.归档复杂对象
第一步:准备数据,并赋值
Person* person = [[Person alloc] init];
person.name = @"kk";
person.age = 16;
第二步:需要创建一个可变的data对象,用来存放归档好的Person对象(为什么是可变的data对象,是因为归档过程是在原对象上进行操作,一点一点归档)
NSMutableData* mData = [[NSMutableData alloc] init];
第三步:准备归档工具
参数为要承接归档完成的复杂对象
NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:mData];
第四步:开始归档
第一个参数:要归档的复杂对象
第二个参数:标记,为了反归档使用
[archiver encodeObject:person forKey:@"person"];
第五步:完成归档,一定要调用下面这个方法,要不然mData中不会有值
[archiver finishEncoding];
第六步:将归档好的数据写入目录中
NSString* personPath = [[SandBoxPaths documentsPath] stringByAppendingPathComponent:@"person.data"];
[mData writeToFile:personPath atomically:YES];
5.反归档复杂对象
第一步:读取归档好的文件的路径
NSString* personPath = [[SandBoxPaths documentsPath] stringByAppendingPathComponent:@"person.data"];
第二步:将归档文件中的data数据读取出来,以便反归档使用
NSData* data = [NSData dataWithContentsOfFile:personPath];
第三步:准备反归档工具
参数:要反归档的data对象
NSKeyedUnarchiver* unArchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
第四步:开始反归档
Person* person = [unArchiver decodeObjectForKey:@"person"];
第五步:反归档完成
[unArchiver finishDecoding];
NSUserDefaults
1.NSUserDefaults:是一个单例,在整个程序中只有一个实例对象,它可以用于数据的永久保存,简单实用
2.NSUserDefaults支持的数据类型:NSNumber(NSInteger、float、double),NSString,NSData,NSArray,NSDictionary,BOOL
3.将数据永久保存到NSUserDefaults
[[NSUserDefaults standardUserDefaults] setObject:@"kk" forKey:@"name"];
4.将数据取出也简单只需取出key对应的值就好了
NSString* name = [[NSUserDefaults standardUserDefaults] objectForKey:@"name"];
注意:对相同的key赋值约等于一次覆盖,要保证每一个key的唯一性
5.值得注意的是:NSUserDefaults存储的对象全是不可变的(这一点非常关键,弄错的话程序会出bug)
6.NSUserDefaults是存储到preferences文件夹下,在该文件夹下以plist格式存在,只能存储简单对象!!
网友评论