zoukankan      html  css  js  c++  java
  • 归档 Archive、解档Unchive、 XML(一)

     

    1 使用归档的方式保存文件

    1.1 问题

    归档是任何对象都可以实现的更常规的方式,可以进行归档的对象需要实现NSCoding协议,而且每个实例变量应该是基本数据类型或者是实现NSCoding协议的某个类的实例。本案例使用归档NSKeyedArchiver和反归档NSKeyedUnarchiver将TRPerson对象写入和读取文件。

    1.2 方案

    首先创建一个TRPerson类,继承至NSObject,该类有两个属性NSString类型的name和NSInteger类型的age。

    其次TRPerson遵守NSCoding协议,实现协议方法initWithCoder:和encodeWithCoder:,initWithCoder:方法主要实现解码,encodeWithCoder:方法主要实现编码。

    然后在main函数中创建三个TRPerson对象,并且放入persons数组中保存,persons数组就是需要进行归档的对象。

    首先实现数据归档,先需要创建一个NSMutableData对象mdata,用于存放归档之后的数据。然后创建NSKeyedArchiver对象archiver,使用initForWritingWithMutableData:方法进行初始化,data参数传递的就是刚才创建的mdata对象。

    再使用encodeObject:forKey:方法进行编码,编码需要指定一个key,反归档时也需要用的这个key,两个可以要保持一致,这里将key设置为“person”。最后使用finishEncoding结束编码。

    使用writeToFile:atomically:方法将mdata写入到本地文件保存。

    然后实现数据的反归档,先使用dataWithContentsOfFile:获取一个data对象,然后创建NSKeyedUnarchiver对象unarchiver,使用initForReadingWithData:进行初始化,data参数就是刚才获取的data对象。

    再使用decodeObjectForKey:方法进行解码获取到一个数组对象persons2,解码时的key要与编码时使用的key保持一致,所以这里的key参数传递“person”。最后使用finishDecoding结束解码。

    最后将persons2数组输出,在控制台查看结果。

    1.3 步骤

    实现此案例需要按照如下步骤进行。

    步骤一:创建TRPerson类

    首先创建一个TRPerson类,继承至NSObject,该类有两个属性NSString类型的name和NSInteger类型的age,代码如下所示:

     
    1. @interface TRPerson : NSObject <NSCoding>
    2. @property (nonatomic, copy) NSString * name;
    3. @property (nonatomicNSInteger age;
    4. @end

    其次TRPerson遵守NSCoding协议,实现协议方法initWithCoder:和encodeWithCoder:,initWithCoder:方法主要实现解码,encodeWithCoder:方法主要实现编码,代码如下所示:

     
    1. (id)initWithCoder:(NSCoder *)aDecoder
    2. {
    3. self [super init];
    4. if (self{
    5. //解码
    6. self.name [aDecoder decodeObjectForKey:@"name"];
    7. self.age [aDecoder decodeIntegerForKey:@"age"];
    8. }
    9. return self;
    10. }
    11. (void)encodeWithCoder:(NSCoder *)aCoder
    12. {
    13. //编码
    14. [aCoder encodeObject:self.name forKey:@"name"];
    15. [aCoder encodeInteger:self.age forKey:@"age"];
    16. }

    然后重写description方法,方便TRPerson信息的输出,代码如下所示:

     
    1. -(NSString *)description {
    2. return [NSString stringWithFormat:@"name:%@,age:%d",self.name,self.age];
    3. }

    最后在main函数中创建三个TRPerson对象,并且放入persons数组中保存,persons数组就是需要进行归档的对象,代码如下所示:

    1. int main(int argcconst char * argv[]) {
    2. @autoreleasepool {
    3. TRPerson *person1 [[TRPerson alloc]init];
    4. person1.name = @"zhangsan";
    5. person1.age 20;
    6. TRPerson *person2 [[TRPerson alloc]init];
    7. person2.name = @"lisi";
    8. person2.age 18;
    9. TRPerson *person3 [[TRPerson alloc]init];
    10. person3.name = @"wangwu";
    11. person3.age 22;
    12. NSArray *persons = @[person1,person2,person3];
    13. }
    14. return 0;
    15. }

    步骤二:数据归档

    首先需要创建一个NSMutableData对象mdata,用于存放归档之后的数据。然后创建NSKeyedArchiver对象archiver,使用initForWritingWithMutableData:方法进行初始化,data参数传递的就是刚才创建的mdata对象,代码如下所示:

    1. //创建可变的data对象,需要写入数据
    2. NSMutableData *mdata [NSMutableData data];
    3. //创建归档对象archiver
    4. NSKeyedArchiver *archiver [[NSKeyedArchiver alloc]initForWritingWithMutableData:mdata];

    然后使用encodeObject:forKey:方法进行编码,编码需要指定一个key,反归档时也需要用的这个key,两个可以要保持一致,这里将key设置为“person”,代码如下所示:

    1. //编码
    2. [archiver encodeObject:persons forKey:@"person"];

    完成编码之后使用finishEncoding结束归档,代码如下所示:

    1. //结束编码
    2. [archiver finishEncoding];

    最后使用writeToFile:atomically:方法将mdata写入到本地文件保存,代码如下所示:

    1. [mdata writeToFile:@"/Users/Tarena/Desktop/person" atomically:YES];

    运行程序桌面上增加一个名为person的文件,存储的数据就是刚才归档的persons数组,如图-1所示:

    图-1

    步骤二:数据反归档

    首先使用dataWithContentsOfFile:获取一个data对象,然后创建NSKeyedUnarchiver对象unarchiver,使用initForReadingWithData:进行初始化,data参数就是刚才获取的data对象,代码如下所示:

    1. //获取文件数据
    2. NSData *data [NSData dataWithContentsOfFile:@"/Users/Tarena/Desktop/person"];
    3. //创建反归档对象unarchiver
    4. NSKeyedUnarchiver *unarchiver [[NSKeyedUnarchiver alloc]initForReadingWithData:data];

    然后使用decodeObjectForKey:方法进行解码获取到一个数组对象persons2,解码时的key要与编码时使用的key保持一致,所以这里的key参数传递“person”,完成解码之后使用finishDecoding结束反归档,代码如下所示:

    1. //解码
    2. NSArray *persons2 [unarchiver decodeObjectForKey:@"person"];
    3. //结束解码
    4. [unarchiver finishDecoding];
    5. NSLog(@"%@",persons2);

    最后运行程序将persons2数组输出,在控制台查看结果和persons保存的数据一样,如图-2所示:

    图-2

    1.4 完整代码

    本案例中,main.m文件中的完整代码如下所示:

     
    1. #import <Foundation/Foundation.h>
    2. #import "TRPerson.h"
    3. int main(int argcconst char * argv[]) {
    4. @autoreleasepool {
    5. TRPerson *person1 [[TRPerson alloc]init];
    6. person1.name = @"zhangsan";
    7. person1.age 20;
    8. TRPerson *person2 [[TRPerson alloc]init];
    9. person2.name = @"lisi";
    10. person2.age 18;
    11. TRPerson *person3 [[TRPerson alloc]init];
    12. person3.name = @"wangwu";
    13. person3.age 22;
    14. NSArray *persons = @[person1,person2,person3];
    15. //创建可变的data对象,需要写入数据
    16. NSMutableData *mdata [NSMutableData data];
    17. //创建归档对象archiver
    18. NSKeyedArchiver *archiver [[NSKeyedArchiver alloc]initForWritingWithMutableData:mdata];
    19. //编码
    20. [archiver encodeObject:persons forKey:@"person"];
    21. //结束编码
    22. [archiver finishEncoding];
    23. [mdata writeToFile:@"/Users/Tarena/Desktop/person" atomically:YES];
    24. //获取文件数据
    25. NSData *data [NSData dataWithContentsOfFile:@"/Users/Tarena/Desktop/person"];
    26. //创建反归档对象unarchiver
    27. NSKeyedUnarchiver *unarchiver [[NSKeyedUnarchiver alloc]initForReadingWithData:data];
    28. //解码
    29. NSArray *persons2 [unarchiver decodeObjectForKey:@"person"];
    30. //结束解码
    31. [unarchiver finishDecoding];
    32. NSLog(@"%@",persons2);
    33. }
    34. return 0;
    35. }
     

    2 使用NSXML框架解析XML文件

    2.1 问题

    XML可扩展标记语言,是一种运用于各种计算机语言中的非常重要的数据交换格式,属性列表(plist)就是以XML形式存储的,本案例演示如何使用XML框架解析XML文件。

    2.2 方案

    首先准备一个XML文件,该XML文件保存的是图书的信息,包括书名、作者、价钱以及页数,如图-3所示:

    图-3

    其次创建一个Book类用于保存解析出来的图书信息,该类继承至NSObject,有如下属性:

    NSString类型的name,用于保存书名;

    NSString类型的author,用于保存图书作者;

    int类型的page,用于保存图书的页数;

    int类型的price,用于保存图书的价钱。

    然后创建一个MyParser类继承至NSObject,该类需要遵守NSXMLParserDelegate协议,主要通过实现协议方法完成XML文件的解析。

    MyParser类有如下属性和方法:

    NSMutableArray类型的books,用于保存解析出来的全部Book对象;

    Book类型的currentBook,用于保存当前正在解析的Book对象;

    NSString的currentString,用于保存当前正在解析的内容;

    -(NSMutableArray*)getBooksByData:(NSData *)data方法的功能主要是创建NSXMLParser对象parser,进行XML文件解析获取到全部的Book对象,该方法中需要将parser的委托对象delegate指定为self。

    最后在MyParser类中分别实现相关的协议方法,完成XML文件的解析。在main函数中就可以直接通过MyParser的getBooksByData:方法获取到所有的图书对象。

    2.3 步骤

    实现此案例需要按照如下步骤进行。

    步骤一:创建Book对象

    首先创建一个Book类用于保存解析出来的图书信息,该类继承至NSObject,代码如下所示:

     
    1. @interface Book : NSObject
    2. @property (nonatomic, retainNSString *name;
    3. @property (nonatomic, retainNSString *author;
    4. @property (nonatomic, assignint page;
    5. @property (nonatomic, assignint price;
    6. @end

    为了方便输出Book信息,在Book类中重写description方法,代码如下所示:

    1. -(NSString *)description {
    2. return [NSString stringWithFormat:@"name:%@,author:%@,price:%d,page:%d",self.name,self.author,self.price,self.page];
    3. }

    步骤二:MyParser类

    首先创建一个MyParser类继承至NSObject,该类需要遵守NSXMLParserDelegate协议,主要通过实现协议方法完成XML文件的解析,代码如下所示:

     
    1. @interface MyParser : NSObject<NSXMLParserDelegate>
    2. @property (nonatomic, retain)NSMutableArray *books;
    3. @property (nonatomic, retain)Book *currentBook;
    4. @property (nonatomic, retain)NSString *currentString;
    5. -(NSMutableArray*)getBooksByData:(NSData *)data;
    6. @end

    其次实现getBooksByData:方法,该方法的功能主要是创建NSXMLParser对象parser,进行XML文件解析获取到全部的Book对象,该方法中需要将parser的委托对象delegate指定为self,代码如下所示:

     
    1. -(NSMutableArray *)getBooksByData:(NSData *)data{
    2. self.books [NSMutableArray array];
    3. NSXMLParser *parser [[NSXMLParser alloc]initWithData:data];
    4. parser.delegate = self;
    5. //XML解析
    6. [parser parse];
    7. return self.books;
    8. }

    然后在MyParser类中分别实现相关的协议方法,完成XML文件的解析,首先需要实现parser:didStartElement:namespaceURI:qualifiedName:attributes:方法,该方法在遇到开始标签时被调用,因此需要在该方法中创建一个Book对象,用于保存当前正在解析的的图书信息,代码如下所示:

     
    1. //遇到一个开始标签时触发
    2. (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qNameattributes:(NSDictionary *)attributeDict{
    3. if ([elementName isEqualToString:@"book"]) {
    4. self.currentBook [[Book alloc]init];
    5. }
    6. }

    其次实现parser:foundCharacters:方法,该方法在遇到字符串时被调用,因此需要在该方法中保存当前获取到的信息,该信息即是图书的某个属性内容,代码如下所示:

    1. //遇到字符串时触发
    2. -(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
    3. //获取当前信息
    4. self.currentString = string;
    5. }

    再实现parser:didEndElement:namespaceURI:qualifiedName:方法,该方法在遇到结束标签时被调用,因此该方法中需要根据结束标签的内容确定self.currentString记录的信息是当前图书的具体哪一个属性的内容,代码如下所示:

     
    1. //遇到结束标签时触发
    2. -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
    3. //根据结束标签将self.currentString赋值给相应的图书信息
    4. if ([elementName isEqualToString:@"name"]) {
    5. self.currentBook.name = self.currentString;
    6. }else if ([elementName isEqualToString:@"author"]) {
    7. self.currentBook.author = self.currentString;
    8. }else if ([elementName isEqualToString:@"price"]) {
    9. self.currentBook.price [self.currentString intValue];
    10. }else if ([elementName isEqualToString:@"page"]) {
    11. self.currentBook.page [self.currentString intValue];
    12. }else if ([elementName isEqualToString:@"book"]){
    13. [self.books addObject:_currentBook];
    14. }
    15. }

    实现以上方法就完成了XML文件的解析,最后在main函数中直接通过MyParser的getBooksByData:方法获取到所有的图书对象,代码如下所示:

     
    1. int main(int argcconst char * argv[]) {
    2. @autoreleasepool {
    3. MyParser *parser [[MyParser alloc]init];
    4. NSMutableArray *books [parser getBooksByData:[NSData dataWithContentsOfFile:@"/Users/Tarena/Desktop/books.xml"]];
    5. for (Book *book in books{
    6. NSLog(@"%@",book);
    7. }
    8. }
    9. return 0;
    10. }

    运行程序,在控制台输出所有图书的信息,如图-4所示:

    图-4

    2.4 完整代码

    本案例中,main.m文件中的完整代码如下所示:

     
    1. #import <Foundation/Foundation.h>
    2. #import "MyParser.h"
    3. #import "Book.h"
    4. int main(int argcconst char * argv[]) {
    5. @autoreleasepool {
    6. MyParser *parser [[MyParser alloc]init];
    7. NSMutableArray *books [parser getBooksByData:[NSData dataWithContentsOfFile:@"/Users/Tarena/Desktop/books.xml"]];
    8. for (Book *book in books{
    9. NSLog(@"%@",book);
    10. }
    11. }
    12. return 0;
    13. }
     

    本案例中,MyParser.h文件中的完整代码如下所示:

     
    1. #import <Foundation/Foundation.h>
    2. #import "Book.h"
    3. @interface MyParser : NSObject<NSXMLParserDelegate>
    4. @property (nonatomic, retain)NSMutableArray *books;
    5. @property (nonatomic, retain)Book *currentBook;
    6. @property (nonatomic, retain)NSString *currentString;
    7. -(NSMutableArray*)getBooksByData:(NSData *)data;
    8. @end
     

    本案例中,MyParser.m文件中的完整代码如下所示:

     
    1. #import "MyParser.h"
    2. #import "Book.h"
    3. @implementation MyParser
    4. -(NSMutableArray *)getBooksByData:(NSData *)data{
    5. self.books [NSMutableArray array];
    6. NSXMLParser *parser [[NSXMLParser alloc]initWithData:data];
    7. parser.delegate = self;
    8. //XML解析
    9. [parser parse];
    10. return self.books;
    11. }
    12. //遇到一个开始标签时触发
    13. (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qNameattributes:(NSDictionary *)attributeDict{
    14. if ([elementName isEqualToString:@"book"]) {
    15. self.currentBook [[Book alloc]init];
    16. }
    17. }
    18. //遇到字符串时触发
    19. -(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
    20. //获取当前信息
    21. self.currentString = string;
    22. }
    23. //遇到结束标签时触发
    24. -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
    25. //根据结束标签将self.currentString赋值给相应的图书信息
    26. if ([elementName isEqualToString:@"name"]) {
    27. self.currentBook.name = self.currentString;
    28. }else if ([elementName isEqualToString:@"author"]) {
    29. self.currentBook.author = self.currentString;
    30. }else if ([elementName isEqualToString:@"price"]) {
    31. self.currentBook.price [self.currentString intValue];
    32. }else if ([elementName isEqualToString:@"page"]) {
    33. self.currentBook.page [self.currentString intValue];
    34. }else if ([elementName isEqualToString:@"book"]){
    35. [self.books addObject:_currentBook];
    36. }
    37. }
    38. @end
     

    本案例中,Book.h文件中的完整代码如下所示:

     
    1. #import <Foundation/Foundation.h>
    2. @interface Book : NSObject
    3. @property (nonatomic, retainNSString *name;
    4. @property (nonatomic, retainNSString *author;
    5. @property (nonatomic, assignint page;
    6. @property (nonatomic, assignint price;
    7. @end
     

    本案例中,Book.m文件中的完整代码如下所示:

     
    1. @implementation Book
    2. -(NSString *)description {
    3. return [NSString stringWithFormat:@"name:%@,author:%@,price:%d,page:%d",self.name,self.author,self.price,self.page];
    4. }
    5. @end
  • 相关阅读:
    无线渗透开启WPS功能的路由器
    写代码怎能不会这些Linux命令?
    分布式服务框架 Zookeeper -- 管理分布式环境中的数据
    每天进步一点点——五分钟理解一致性哈希算法(consistent hashing)
    Innodb 中的事务隔离级别和锁的关系
    线上操作与线上问题排查实战
    MySQL 四种事务隔离级的说明
    一次由于 MTU 设置不当导致的网络访问超时
    SYN 和 RTO
    The story of one latency spike
  • 原文地址:https://www.cnblogs.com/hytx/p/5051925.html
Copyright © 2011-2022 走看看