Loading

plist文件读写,序列化与反序列化,文件的读写[xcode4.4.1]

这篇学习目标:

  1. plist文件读写
  2. 对象序列化与反序列化
  3. 本地文件的读写
  4. iCloud存储的API

引言

  在做iOS开发时,经常用到到plist文件,  那plist文件是什么呢? 它全名是:Property List,属性列表文件,它是一种用来存储串行化后的对象的文件。属性列表文件的扩展名为.plist ,因此通常被称为 plist文件。文件是xml格式的。plist文件通常用于储存用户设置,也可以用于存储捆绑的信息。
  有时需要把某个对象进行序列化后存储起来,也需要反序列化读取数据。

  关于Core Data框架,本篇不说,如果有机会,后面有博客详细说明。

 

一、plist 文件读取与写入

  plist 文件创建、写入内容。内容比较简单,我直接用代码加注释的方式来表达,亲,OK啦!

      plist 支持的数据类型有 Array、Dictionary、Boolean、Data、Date、Number、String这些类型,其他的类型支持,所以一般需要转化一下再存。记住plist本质上是一个XML。

PList 文件创建、读、写入等操作
 1 - (void)viewDidLoad
 2 {
 3     [super viewDidLoad];
 4     
 5     //获取应用程序沙盒的Documents目录
 6     NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
 7     NSString *p = [paths objectAtIndex:0];    
 8     NSString *filename = [p stringByAppendingPathComponent:@"Sample.plist"];        
 9         
10     // 创建文件管理对象
11     NSFileManager *fm = [NSFileManager defaultManager];
12     if ([fm fileExistsAtPath:filename])  // 判断文件是否存在
13     {
14         NSError *error;
15         [fm removeItemAtPath:filename error:&error];  // 删除旧文件
16         NSLog(@"%@",error);
17     }
18     
19     // 创建文件零字节的文件
20     [fm createFileAtPath:filename contents:nil attributes:nil];
21     
22     // 创建一个Dictionary (注:NSMutableDictionary同NSDictionary,主要区分:可变与不可变)   
23     //NSDictionary *dict = [NSDictionary dictionaryWithObject:@"一条龙" forKey:@"Year"];
24     NSMutableDictionary *dict = [NSMutableDictionary dictionary];
25     
26     //数据类型可以是:Array、Dictionary、Boolean、Data、Date、Number、String
27     
28     // 新增一条 String 数据
29     NSString *name = @"周星驰(Stephen Chow)";
30     [dict setObject:name forKey:@"姓名"];
31     
32     // 新增一条 Number 数据
33     NSNumber *year = [NSNumber numberWithInt:100];
34     [dict setObject:year forKey:@"影片产量"];
35     
36     // 新增一条 Date 数据
37     NSDate *date = [NSDate date];  //获取当前时间
38     [dict setObject:date forKey:@"时间"];
39     
40     // 新增一条 Data 数据
41     // NSData类提供了一种简单的方式,它用来设置缓冲区、将文件的内容读入缓冲区,或将缓冲区的内容写到一个文件。 对于32位应用程序,NSData缓存区最多可以存储2GB的数据。
42     // 还可以存放图片内容,请你们自己测试一下
43     NSString *d = @"NSData类提供了一种简单的方式,它用来设置缓冲区、将文件的内容读入缓冲区,或将缓冲区的内容写到一个文件。 对于32位应用程序,NSData缓存区最多可以存储2GB的数据。";
44     NSData *data = [d dataUsingEncoding:NSUTF8StringEncoding];
45     [dict setObject:data forKey:@"简介"];
46     
47     // 新增一条 BOOL 数据,Obj-C布尔型是以数字存储的
48     [dict setObject:[NSNumber numberWithBool:YES] forKey:@"搞笑"];
49     
50     // 新增一条 Array 数据
51     NSMutableArray *array = [[NSMutableArray alloc] init];    
52     [array addObject:@"西游·降魔篇 ( 2012)"];
53     [array addObject:@"长江7号 ( 2007)"];
54     [array addObject:@"功夫 ( 2004)"];
55     [array addObject:@"少林足球 ( 2001)"];
56     [array addObject:@"千王之王 ( 1999)"];
57     [array addObject:@"喜剧之王 ( 1999)"];
58     [array addObject:@"行运一条龙 ( 1998)"];
59     [array addObject:@"算死草 ( 1997)"];
60     [array addObject:@"97家有喜事 ( 1997)"];
61     [array addObject:@"食神 ( 1996)"];
62     [array addObject:@"大内密探零零发 ( 1996)"];
63     [array addObject:@"百变星君 ( 1995)"];
64     [array addObject:@"回魂夜 ( 1995)"];
65     [array addObject:@"大话西游之月光宝盒 ( 1995)"];
66     [array addObject:@"国产凌凌漆 ( 1994)"];
67     [array addObject:@"九品芝麻官之白面包青天 ( 1994)"];
68     [array addObject:@"破坏之王 ( 1994)"];
69     [array addObject:@"济公 ( 1993)"];
70     [array addObject:@"唐伯虎点秋香 ( 1993)"];
71     [array addObject:@"逃学威龙3龙过鸡年 ( 1993)"];
72     [array addObject:@"审死官 ( 1993)"];
73     
74     [dict setValue:array forKey:@"作品集"];
75     
76     // 新增 Dictionary 数据,这里就偷个懒,把前的字典内容添加到一个对象中,然后再添加
77     NSDictionary *test = [NSDictionary dictionaryWithDictionary:dict];
78     [dict setValue:test forKey:@"字典"];
79     
80     // 写入文件
81     [dict writeToFile:filename atomically:YES];
82     
83     // 读取数据到对象中
84     NSMutableDictionary *readDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filename ];
85     
86     // 读到指定的值
87     NSLog(@"key '姓名:' is %@",[readDict objectForKey:@"姓名"]);
88     
89     // 输出全部内容
90     NSLog(@"data is:%@",readDict);
91     
92     NSLog(@"File Name:%@",filename);
93 }

到模拟器的目录下查看操作结果:

具体文件所在位置,可以通过NSLog打印出来的地址,进行查找

如果找不到路径,可能是MAC系统隐藏部分文件,可以通过以下命令显示出来:

显示或隐藏文件
1 显示Mac隐藏文件的命令:defaults write com.apple.finder AppleShowAllFiles -bool true
2 隐藏Mac隐藏文件的命令:defaults write com.apple.finder AppleShowAllFiles -bool false
3 
4 或者
5 
6 显示Mac隐藏文件的命令:defaults write com.apple.finder AppleShowAllFiles YES
7 隐藏Mac隐藏文件的命令:defaults write com.apple.finder AppleShowAllFiles NO

重启Finder:鼠标单击窗口左上角的苹果标志-->强制退出-->Finder-->重新启动,就可以找到生成的文件

 

二、对象序列化与反序列化

  为什么要进行对象的序列化操作呢?将内存中的对象实例保存成binary到 磁盘,并且可以逆向这个过程用来保存各操作状态或恢复时数据。亲,大家都懂的,在这就不多说了。

  1. 序列化对象:NSKeyedArchiver
  2. 反序列化对象:NSKeyedUnarchiver

具体代码如下:

序列化与反序列化
 1 - (void)viewDidLoad
 2 {
 3     // 创建一个数组
 4     NSMutableArray *array = [[NSMutableArray alloc] init];
 5     [array addObject:@"西游·降魔篇 ( 2012)"];
 6     [array addObject:@"长江7号 ( 2007)"];
 7     [array addObject:@"功夫 ( 2004)"];
 8     [array addObject:@"少林足球 ( 2001)"];
 9     [array addObject:@"千王之王 ( 1999)"];
10     [array addObject:@"喜剧之王 ( 1999)"];
11     [array addObject:@"行运一条龙 ( 1998)"];
12     
13     // 获取应用程序沙盒的Documents目录
14     NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
15     NSString *p = [paths objectAtIndex:0];
16     NSString *filename = [p stringByAppendingPathComponent:@"State.data"];
17     
18     // 序列化并保存到文件中
19     [NSKeyedArchiver archiveRootObject:array toFile:filename];
20     
21     
22     // 反序列化并加载数据
23     NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithFile: filename];
24     NSLog(@"str:%@", [arr objectAtIndex:0]);
25     NSLog(@"str:%@", [arr objectAtIndex:1]);
26 }

是不是非常简单,同样会生成一个二进制的文件存放在Documents目录下,同学们,自己找一找,这里就没图了。

对一些特殊需求的同学会问:有没有办法可以把自己设计的类进行序列化,并且加密?答案是:肯定可以。只要实现NSCoding协议就可以。

NSCoding是什么呢?

  NSCoding是一个可以由你自行实现的协议,通过扩展你的数据类(data class)来支持encode和decode功能就可以了。它们的任务是把数据写到数据缓存,最后持久保存到磁盘中。

实现很简单,第一步:

继承协议NSCoding
1 @interface CustomData : NSObject<NSCoding>
2 
3 @property (nonatomic,retain) NSString *title;
4 @property (nonatomic,retain) NSString *content;
5 
6 -(id)initWithTitle:(NSString *)tit Content:(NSString *)cont;

第二步,具体实现,也很简单,直接在代码中注解了

具体实现协议
 1 @implementation  CustomData
 2 
 3 @synthesize title;
 4 @synthesize content;
 5 
 6 -(id)initWithTitle:(NSString *)tit Content:(NSString *)cont
 7 {
 8     if ((self = [super init])) {
 9         title = [tit copy];
10         content = [cont copy];
11     }
12     return self;    
13 }
14 
15 
16 #pragma mark 实现 NSCoding 协议
17 #define keyTitle       @"Title"
18 #define keyContent     @"Content"
19 
20 // 编码
21 -(void)encodeWithCoder:(NSCoder *)aCoder{
22     [aCoder encodeObject:title forKey:keyTitle];
23     [aCoder encodeObject:content forKey:keyContent];
24 }
25 
26 // 解码
27 -(id)initWithCoder:(NSCoder *)aDecoder
28 {
29     NSString *t = [aDecoder decodeObjectForKey:keyTitle];
30     NSString *c = [aDecoder decodeObjectForKey:keyContent];
31     return [self initWithTitle:t Content:c];
32 }
33 
34 @end

第三步,调用自定义类

调用自定义类
 1 - (void)viewDidLoad
 2 {
 3     [super viewDidLoad];
 4     //获取应用程序沙盒的Documents目录
 5     NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
 6     NSString *p = [paths objectAtIndex:0];
 7     NSString *filename = [p stringByAppendingPathComponent:@"encode.data"];
 8     
 9     // 创建文件管理对象
10     NSFileManager *fm = [NSFileManager defaultManager];
11     if ([fm fileExistsAtPath:filename])  // 判断文件是否存在
12     {
13         NSError *error;
14         [fm removeItemAtPath:filename error:&error];  // 删除旧文件
15         NSLog(@"%@",error);
16     }
17     // 创建自定义对象
18     CustomData *d = [[CustomData alloc] initWithTitle:@"标题" Content:@"内容"];
19     
20     // 序列化保存成文件
21     [NSKeyedArchiver archiveRootObject:d toFile:filename];
22     
23     // 反序列化读取文件操作
24     CustomData *ud = [NSKeyedUnarchiver unarchiveObjectWithFile: filename];
25     NSLog(@"Title is:%@ ",ud.title);
26     NSLog(@"Title is:%@ ",ud.content);
27 }

 

三、本地文件的操作

  出于安全的目的,应用程序只能将自己的数据和偏好设置写入到几个特定的位置上。当应用程序被安装到设备上时,系统会为其创建一个家目录。

  1. /Documents/  您应该将所有的应用程序数据文件写入到这个目录下。这个目录用于存储用户数据或其它应该定期备份的信息。iTunes会备份这个目录的内容。
  2. /Library/Preferences  这个目录包含应用程序的偏好设置文件。您不应该直接创建偏好设置文件,而是应该使用NSUserDefaults类或CFPreferences API来取得和设置应用程序的偏好。iTunes会备份这个目录的内容。
  3. /Library/Caches  这个目录用于存放应用程序专用的支持文件,保存应用程序再次启动过程中需要的信息。您的应用程序通常需要负责添加和删除这些文件,但在对设备进行完全恢复的过程中,iTunes会删除这些文件。
  4. /tmp/   这个目录用于存放临时文件,保存应用程序再次启动过程中不需要的信息。当您的应用程序不再需要这些临时文件时,应该将其从这个目录中删除(系统也可能在应用程序不运行的时候清理留在这个目录下的文件)。

  可以用NSSearchPathForDirectoriesInDomains和NSTemporaryDirectory函数来取得Documents、Caches、和tmp目录的准确路径。

具体通过以下代码获取目录:

获取用户目录
 1 - (void)viewDidLoad
 2 {
 3     [super viewDidLoad];
 4     //获取应用程序沙盒的目录
 5     
 6     // 获取 主目录 方法
 7     NSString *home = NSHomeDirectory();
 8     NSLog(@"Home: %@",home);
 9     
10     // 获取 Documents 方法
11     NSArray *document = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
12     NSLog(@"document: %@",[document objectAtIndex:0]);
13    
14     // 获取 PreferencePanes 方法
15     NSArray *preferences = NSSearchPathForDirectoriesInDomains(NSPreferencePanesDirectory, NSUserDomainMask, YES);
16     NSLog(@"preferences: %@",[preferences objectAtIndex:0]);
17     
18     // 获取 Caches 方法
19     NSArray *caches = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
20     NSLog(@"caches: %@",[caches objectAtIndex:0]);
21     
22     // 获取 tmp 方法
23     NSString *tmp = NSTemporaryDirectory();
24     NSLog(@"tmp: %@",tmp);
25 }

有几点建议:

  1. 读写用户偏好设置时,请使用NSUserDefaults类进行操作,后继有博文来详述。
  2. 应用程序的程序包中包含声音、图像、或其它资源,则应该使用NSBundle封装类型来装载资源。
  3. 仿真器上返回的路径与真实设备返回的路径,有可能不一样。

 使用 NSFileManager 管理文件,在此简单列出一些常见方法:

NSFileManager 文件管理
 1 -(void)viewDidLoad
 2 {
 3     NSError *error;
 4     //获取应用程序沙盒的Documents目录
 5     NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
 6     NSString *p = [paths objectAtIndex:0];
 7     NSString *file1 = [p stringByAppendingPathComponent:@"Sample_1.txt"];
 8     NSString *file2 = [p stringByAppendingPathComponent:@"Sample_2.txt"];
 9     NSString *file3 = [p stringByAppendingPathComponent:@"Sample_3.txt"];
10     NSString *file4 = [p stringByAppendingPathComponent:@"Sample_4.txt"];
11     
12     // 从网站上获取内容
13     NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.chinapcc.com"]];
14     
15     // 创建文件管理对象
16     NSFileManager *fm = [NSFileManager defaultManager];
17     if (![fm fileExistsAtPath:file1])  // 判断文件是否存在
18     {
19         // 文件不存在,将创建
20         [fm createFileAtPath:file1 contents:data attributes:nil];
21     }
22     
23     //输出文件内容
24     NSLog(@"%@",[NSString stringWithContentsOfFile:file1 encoding:NSUTF8StringEncoding error:&error]);
25 
26     // 读取出文件1的内容
27     NSData *data2 =[fm contentsAtPath:file1];
28     if ([fm fileExistsAtPath:file2])  // 判断文件是否存在
29     {
30         //删除文件file2
31         [fm removeItemAtPath:file2 error:&error];
32     }
33     
34     // 创建文件2
35     [fm createFileAtPath:file2 contents:data2 attributes:nil];
36         
37     // 文件1 复制成 文件2 对文件复制
38     [fm copyItemAtPath:file1 toPath:file3 error:&error];
39     
40     // 文件3 改名为 文件4 对文件进行移动,在同一目录,就可理解为改名
41     [fm moveItemAtPath:file3 toPath:file4 error:&error];
42     
43     //下面是目录枚举 这种方法会递归
44     NSDirectoryEnumerator *dir= [fm enumeratorAtPath:NSHomeDirectory()];
45     NSString *path=[NSString new];
46     while ((path=[dir nextObject])!=nil) {
47         NSLog(@"%@",path);
48     }    
49 }

三、iCloud存储的API

  1. iCloud document storage,利用iCloud存储用户文件,比如保存一些用户在使用应用时生成的文件,如数据库文件等;
  2. iCloud key-value data storage,利用iCloud存储键值对,主要是保存一些程序的设置信息,一般只允许存储几十K大小。

  应用主目录下的Document目录和Library目录(除了该目录下的Caches)的文件都会被自动的备份到iCloud,因此,可以把较大的临时文件或随时可以重建的文件放在Library\Caches目录下,就可以帮用户节省iCloud空间,提供用户体验。另外,相信大家都关心,应用存放在iCloud上如何保证安全呢,不用的应用保存的数据是否能够有效隔离?这一点,iCloud引入了iOS下沙盒的概念,即每一个应用在iCloud上都有一个沙盒,访问的范围就被限制在这里面,从而保证数据安全和隔离。

  iCloud目前只能在真实设备中测试,不能在Simulator中测试,所以在此只提一些概念,具体操作,后面有一篇完整的博文详细来实战,请大家期待。

 

 

  明天是清明节,我有好多年没有在家里过清明节,也没有机会扫墓,按我老家说是上坟,突然就想起我爷爷与外婆,祝他们在天国过得更好。

  明天开车回老家,想家。

posted @ 2013-04-03 22:35  草梵  阅读(1478)  评论(3编辑  收藏  举报