- 19.4 使用NSData创建自定义档案
- import<Foundation/NSObject.h>
- import<Foundation/NSAutoreleasePool.h>
- import<Foundation/NSString.h>
- import<Foundation/NSKeyedArchiver.h>
- import<Foundation/NSCoder.h>
- import<Foundation/NSData.h>
- import“AddressBook.h”
- import“Foo.h”
- import<Foundation/NSObject.h>
- import<Foundation/NSAutoreleasePool.h>
- import<Foundation/NSString.h>
- import<Foundation/NSKeyedArchiver.h>
- import<Foundation/NSCoder.h>
- import<Foundation/NSData.h>
- import“AddressBook.h”
- import“Foo.h”
19.4 使用NSData创建自定义档案
有时可能不想和前面示例程序一样,使用archiveRootObject:ToFile:方法将对象直接写入文件。比如,可能想收集一些或全部对象,并将其存储到单个档案文件中。在Objective-C中,通过使用名为NSData的通用数据流对象类,可以实现上述功能,在第16章,我们简单地提到过这个类。
正如第16章所提到的,NSData对象可以用来保留一块内存空间以备后来存储数据。这些数据空间的典型应用是作为一些数据的临时存储空间,如随后将被写入文件,或可能用于容纳从磁盘读取的文件内容。创建可变数据空间的最简单方式是使用data方法:
dataArea=[NSMutableData data];
该语句创建一个空缓冲区,其大小随程序执行需要而扩展。
作为一个简单的例子,假设你想将地址簿和一个Foo对象归档到同一个文件。假设对于这个例子,你已经向AddressBook和AddressCard类添加了一个带键的归档方法(参见代码清单19-9)。
代码清单19-9
import<Foundation/NSObject.h>
import<Foundation/NSAutoreleasePool.h>
import<Foundation/NSString.h>
import<Foundation/NSKeyedArchiver.h>
import<Foundation/NSCoder.h>
import<Foundation/NSData.h>
import“AddressBook.h”
import“Foo.h”
int main(int argc, char*argv[])
{
NSAutoreleasePool*pool=[[NSAutoreleasePool alloc]init];
Foo*myFoo1=[[Foo alloc]init];
Foo*myFoo2;
NSMutableData*dataArea;
NSKeyedArchiver*archiver;
AddressBook*myBook;
//Insert code from Program 19.7 to create an Address Book
//in myBook containing four address cards
[myFoo1 setStrVal:@“This is the string”];
[myFoo1 setIntVal:12345];
[myFoo1 setFloatVal:98.6];
//Set up a data area and connect it to an NSKeyedArchiver object
dataArea=[NSMutableData data];
archiver=[[NSKeyedArchiver alloc]
initForWritingWithMutableData:dataArea];
//Now we can begin to archive objects
[archiver encodeObject:myBook forKey:@“myaddrbook”];
[archiver encodeObject:myFoo1 forKey:@“myfoo1”];
[archiver finishEncoding];
//Write the archived data area to a file
if([dataArea writeToFile:@“myArchive”atomically:YES]==NO
NSLog(@“Archiving failed!”);
[archiver release];
[myFoo1 release];
[pool drain];
return 0;
}
分配一个NSKeyedArchiver对象之后,发送initForWritingWithMutableData:消息,以指定要写入归档数据的存储空间。这就是前面创建的NSMutabledata空间dataArea。此时,就可以向存储在archiver中的NSKeyedArchiver对象发送编码消息,以归档该程序中的对象。实际上,所有编码消息在收到finishEncoding消息之前都被归档并存储在指定的数据空间内。
这里,有两个对象需要编码—一个是地址簿,另一个是Foo对象。对于这些对象可以使用encodeObject:forKey:,因为在前面你已经为AddressBook、AddressCard和Foo类实现了编码方法和解码方法(理解这个概念很重要)。
在归档这两个对象时,向archiver对象发送一条finishEncoding消息。之后,就不能编码其他对象,你需要发送此消息以完成归档过程。
此时,你预留的那块名为dataArea的空间包含归档对象,这些对象可以一种可写入文件的格式存在。消息表达式
[dataArea writeToFile:@“myArchive”atomically:YES]
向你的数据流发送writeToFile:atomically:encoding:error:消息,请求它把它的数据写入指定文件,这个文件名为myArchive。
从if语句可以看到,writeToFile:atomically:encoding:error:方法返回一个BOOL值:如果写操作成功就返回YES,如果失败(可能是指定了无效的路径名或文件系统已满)就返回NO。
从档案文件中恢复数据很简单—所做的工作只需和归档文件相反。首先,需要像以前那样分配一个数据空间。然后,把档案文件中的数据读入该数据空间,然后,需要创建一个NSKeyedUnarchiver对象,并告知它从指定空间解码数据。必须调用解码方法来提取和解码归档的对象,做完之后,向NSKeyedUnarchiver对象发送一条finishDecoding消息。
代码清单19-10实现了所有任务。
代码清单19-10
import<Foundation/NSObject.h>
import<Foundation/NSAutoreleasePool.h>
import<Foundation/NSString.h>
import<Foundation/NSKeyedArchiver.h>
import<Foundation/NSCoder.h>
import<Foundation/NSData.h>
import“AddressBook.h”
import“Foo.h”
int main(int argc, char*argv[])
{
NSAutoreleasePool*pool=[[NSAutoreleasePool alloc]init];
NSData*dataArea;
NSKeyedUnarchiver*unarchiver;
Foo*myFoo1;
AddressBook*myBook;
//Read in the archive and connect an
//NSKeyedUnarchiver object to it
dataArea=[NSData dataWithContentsOfFile:@“myArchive”];
if(!dataArea){
NSLog(@“Cant read back archive file!”);
return(1);
}
unarchiver=[[NSKeyedUnarchiver alloc]
initForReadingWithData:dataArea];
//Decode the objects we previously stored in the archive
myBook=[unarchiver decodeObjectForKey:@“myaddrbook”];
myFoo1=[unarchiver decodeObjectForKey:@“myfoo1”];
[unarchiver finishDecoding];
[unarchiver release];
//Verify that the restore was successful
[myBook list];
NSLog(“@\n%i\n%g”,[myFoo1 strVal],
[myFoo1 intVal],[myFoo1 floatVal]);
[pool release];
return 0;
}
代码清单19-10输出
========Contents of:Steves Address Book=========
Jamie Baker jbaker@hitmail.com
Julia Kochan
jewls337@axlc.com
Stephen Kochan steve@steve_kochan.com
Tony Iannino tony.iannino@techfitness.com
===================================================
This is the string
12345
98.6
输出结果验证了你的地址簿和Foo对象已成功地从档案文件中恢复了。