Cocoa提供了两个通用的文件处理类:属性列表和对象编码。
在Cocoa中,有一类名为属性列表的对象,常简写为plist。这些列表包含Cocoa知道如何操作的一组对象。具体来讲,Cocoa知道如何将它们保存到文件中并进行加载。属性列表包括NSArray,NSDictionary,NSString,NSNumber,NSData,以及NSDate,以及它们的变体。
NSDate。Cocoa中用于处理日期和时间的基础类。[NSDate date]获取当前的日期和时间,它是一个自动释放对象。
NSData。该类包装了大量字节。你可以获取数据的长度和指向字节起始位置的指针。因为NSData是一个对象,适用于常规的内存管理行为。因此,如果将数据块传递给一个函数或方法,可以通过传递一个自动释放NSData来实现,无需担心内存清除问题。
NSData对象时不可以改变的。它们被创建后就不能改变。可以使用它们,但不能更改其中的内容,可以使用NSMutableData在数据内容中添加和删除字节。
属性列表
集合属性列表类(NSArray、NSDictionary)具有一个-writeToFile:atomically:方法,用于将属性列表写入文件。NSString和NSData也具有writeToFile:atomically:方法,但它只能写出字符串或数据块。
因此,我们可以将字符串存入一个数组,然后保存该数组:
NSArray *phrase;
phrase = [NSArray arrayWithObjects:@”I”,@”seem”,@”to”,@”be”,@”a”,@”verb”,nil];
[phrase writeToFiel:@”/tmp/verbiage.txt” atomically:YES];
现在看一下文件/tmp/veribiage.txt,应该看到如下代码:
<?xml version=”1.0” encoding=”UTF-8”?>
<!DOCTYPE plist PUBLIC “-//Apple/DTD PLIST 1.0//EN”
“http://www.apple.com/DTDs/PropertyList-1.0.dtd”>
<plist version=“1.0>
<array>
<string>I</string>
<string>seem</string>
<string>to</string>
<string>be</string>
<string>a</string>
<string>verb</string>
</array></plist>
现在已将verbiage.txt文件存放在磁盘上,可以使用+arrayWithContentOfFile:方法读取该文件。代码如下所示:
NSArray *phrase2 = [NSArray arrayWithContentOfFile:@”/tmp/verbiage.txt”];writeToFile:方法中的atomically。这个参数的值为BOOL类型,用于通知Cocoa是否应该首先将文件内容保存在临时文件中,当文件成功保存后,再将临时文件和原始文件交换。这是一种安全机制:如果在保存过程中出现意外,不会破坏原始文件。但是这种安全机制需要付出一定的代码:在保存过程中,由于原始文件仍然保存在磁盘中,所以需要使用双倍的磁盘空间。除非保存的文件非常大,将会占用用户硬盘的空间,否则应该自动保存文件。
NSLog(@“%@”,phrase2);
如果能将数据精简为属性列表类型,则可以使用这些非常便捷的调用 来将内容保存到磁盘中,供以后读取。如果你正在从事一项新创意或设计一个新项目,可以使用这些便捷方法来快速编写和运行程序。即使只想把数据块保存在磁盘中,并且根本不需要使用对象,也可以使用NSData来简化工作。只需将数据包装在一个NSData对象中,然后在NSData对象上调用writeToFile:atomically:.
这些函数的一个缺点是, 它们不会返回任何错误信息。如果不能加载文件,只能从方法中得到nil指针,而不能确定出现了何种错误。
编码对象
如果不是属性列表类的对象,则无法使用对应的方法来存储了。针对其他对象,Cocoa提供了其他的方法,和java的序列化和反序列化类似。具体的是NSCoding协议,下面看个简单的例子。
@interface Thingie:NSObject <NSCoding>{
NSString *name;
int magicNumber;
NSMutableArray *subThingies;
}
@property (copy) NSString *name;
@property int magicNumber;
@property (retain) NSMutableArray *subThingies;
@end//Thingie
@implementation Thingie
@synthesize name;
@synthesize magicNumber;
@synthesize subThingies;
-(void) encodeWithCoder: (NScoder *) coder{
[coder encodeObject : name forKey: @"name"];
[coder encodeInt : magicNumber forKey: @"magicNumber"];
[coder encodeObject : subThingies forKey: @"subThingies"];
}//encodeWithCoder
-(id) initWithCoder: (NSCoder *) decoder{
if(self = [super init]){
self.name = [decoder decodeObjectForKey: @"name"];
self.magicNumber = [decoder decodeIntForKey: @"magicNumber"];
self.subThingies = [decoder decodeObjectForKey: @"subThingies"];
}
return(self);
}
initWithCoder:和其他任何init方法一样,在对对象执行操作之前,需要使用超类对它们进行初始化。为此,可以采用两种方式,具体取决于父类。如果父类采用NSCoding协议,则应该调用[super initWithCode: decoder];否则,的只需要调用[super init]即可。
以上就是将类Thingie实现了NSCoding协议,这个类可以进行序列化和反序列化了。
Thingie thing1 = [[Thingie alloc] init];
NSData *freezeDried;
freezeDried = [NSKeyedArchiver archivedDataWithRootObject : thing1];//此处调用了encodeWithCoder,NSData对象就可以进行存储了。
[thing1 release];
thing1 = [NSKeyedUnarchiver unarchiveObjectWithData: freezeDried];//此处调用了initWithCoder。