在开发项目的过程中,我们有可能遇到上面这图片展示的数据。其实这些数据是存放到文件中的二进制数据。记得大学的时候老师带着我们写了一个记账类软件,当时就是把账单里面的数据存放到文件里面。我直接简述那时候是怎么做的。首先得有个账单类。
------------------账单类的头文件-----------------
//
// Payout.h
// NoteTaking
//
// Created by 刘超 on 12-12-3.
// Copyright (c) 2012年刘超. All rights reserved.
//
#import <Foundation/Foundation.h>
#define KAmountKey @"Amount"
#define KTimekey @"Time"
#define KTypeKey @"Type"
#define KCommentKey @"Comment"
@interface Payout : NSObject<NSCoding,NSCopying>
@property (assign,nonatomic)float amount;
@property (strong,nonatomic)NSDate * time;
@property (strong,nonatomic)NSString * type;
@property (strong,nonatomic)NSString * comment;
-(NSString*)setMoth:(NSDate*)datetime;
-(NSString*)getType;
@end
------------------账单类的原文件-----------------
//
// Payout.m
// NoteTaking
//
// Created by 刘超 on 12-12-3.
// Copyright (c) 2012年刘超. All rights reserved.
//
#import "Payout.h"
@implementation Payout
@synthesize amount;
@synthesize time;
@synthesize type;
@synthesize comment;
-(void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeFloat:amountforKey:KAmountKey];
[encoder encodeObject:timeforKey:KTimekey];
[encoder encodeObject:typeforKey:KTypeKey];
[encoder encodeObject:commentforKey:KCommentKey];
}
-(id)initWithCoder:(NSCoder *)decoder
{
if (self=[superinit]) {
amount=[decoderdecodeFloatForKey:KAmountKey];
time=[decoderdecodeObjectForKey:KTimekey];
type=[decoderdecodeObjectForKey:KTypeKey];
comment=[decoderdecodeObjectForKey:KCommentKey];
}
returnself;
}
-(id)copyWithZone:(NSZone *)zone
{
Payout*copy=[[[selfclass]allocWithZone:zone]init];
copy.amount=amount;
copy.time=[self.timecopyWithZone:zone];
copy.type=[self.typecopyWithZone:zone];
copy.comment=[self.commentcopyWithZone:zone];
return copy;
}
-(NSString*)setMoth:(NSDate*)datetime
{
//datetime= self.time;
NSDateFormatter*atime=[[NSDateFormatteralloc]init];
[atime setDateStyle:NSDateFormatterMediumStyle];
[atime setTimeStyle:NSDateFormatterShortStyle];
[atime setDateFormat:@"MM"];
NSString*moth=[atimestringFromDate:self.time];
return moth;
}
@end
这个类的每一个成员变量都遵循了<NSCoping>协议。为什么要实现此协议呢?因为我们数据写到文件中,其事就是一个拷贝的过程,需要进行复制。我们要拷贝一份数据,拷贝后的两份数据互相不影响,是一份独立的克隆体,修改一份中的数据时另一份中的数据不会相互影响。这就需要实现<NSCopying>协议: -( id )copyWithZone:( NSZone *)zone方法或<NSMutableCopying>协议的:- (id)mutableCopyWithZone:(NSZone *)zone。接下来就是要把数据写在文件中,存放到该应用程序沙盒里面。首先得有个路径来存放数据,获取路径的方法如下。
#define KFilenme @"aehive"
-(NSString*)dataFilepath
{
NSArray*paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString*documentDirectory=[pathsobjectAtIndex:0];
return [documentDirectorystringByAppendingPathComponent:KFilenme];
}
接着我们就是要有两个最重要的方法来进行文件的读写操作。我就直接上代码了。
-(void) writeList:(NSMutableArray *) list To:(NSString *) fileName//写的函数
{
NSMutableData*data=[[NSMutableDataalloc]init];//声明一个可变数据类型
NSKeyedArchiver*archiver=[[NSKeyedArchiveralloc]initForWritingWithMutableData:data];//编码
[archiver encodeObject:listforKey:KDataKey];//存放数据文件的类型和名字
[archiver finishEncoding];//编码完成
[data writeToFile:[selfdataFilepath]atomically:YES];//写在相应的路径下
}
-(NSMutableArray *) readListFromFile:(NSString *) fileName//读的函数
{
if ([[NSFileManagerdefaultManager]fileExistsAtPath:fileName])//是否存在要读的数据类型,如果存在
{
NSData*data=[[NSMutableDataalloc]initWithContentsOfFile:fileName];//打开名为fileName数据类型的数据
NSKeyedUnarchiver*unarchiver=[[NSKeyedUnarchiveralloc]initForReadingWithData:data];//解码
NSMutableArray * array = [unarchiverdecodeObjectForKey:KDataKey];//把解码出来的数据存放在可变数组里面
[unarchiver finishDecoding];//解码完成
if (!array) {
array=[[NSMutableArrayalloc]init];
}
return array;//返回该数组
}
return [[NSMutableArrayalloc]init];;//如果不存在名为fileName数据类型直接返回空
}
可以看出这种把数据写到文件中,其实就是利用NSKeyedArchiver归档(将各种类型的对象存到文件中) ,编码后直接调用- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile;写到文件中就可以了。读出来的时候也是调用相应的函数读出来,然后解码。这个存进去的数据就可以完全读出来了。写到这里,可能大家会认为关于文件的读写就完了。其实今天的重点还没有开始。
我们在iOS中NSKeyedArchiver方法来归档数据。数据的读写相对容易得多了。有时候我们拿到的文件是其它平台把一个已经定义好了的结构体等数据以二进制的方式存放到文件中。问题就来了这时候怎么读数据呢?其实这时候我们就要用到下面的方法来对数据进行读的操作。这些数据存储空间里面是有相应的长度的,我们知道了该结构体的定义,就可以知道该结构体的长度,然后就可以把这些数据一个字节一个字节的拷贝出来。这需要我们iOS端有与之相应的结构体。下面这段代码就是对一份文件中存了很多个相同结构的结构数据拷贝出来。大概思想就是我们做了一个循环来读每一个结构体的数据,只要拷贝的总字节小于文件的总字节数。就说明这个数据还没有读到末尾。还用了一个变量来纪录目前读过的总字节数。具体代码如下。
NSString *path = [[NSBundlemain Bundle]pathForResource:@"n9gps"ofType:@"rbb"];
//获取数据
NSData *reader = [NSDatadata WithContentsOfFile:path];
//得到文件的长度(大小)
NSInteger nSize = [reader length];
NSInteger nPos =0;
NSMutableDictionary*dataDic=[[NSMutableDictionaryalloc]init];
char* pBuffer = [readerbytes];
while (nPos<nSize) {
structRMBDM_FRAMEHEADER frameHeader={0};
memcpy(&frameHeader, pBuffer+nPos,sizeof(RMBDM_FRAMEHEADER));
nPos += sizeof(RMBDM_FRAMEHEADER);
structRMBDM_DATETIME dataTime={0};
structRMBDM_GPS dataGps={0};
memcpy(&dataTime, pBuffer+nPos,sizeof(RMBDM_DATETIME));
nPos += sizeof(RMBDM_DATETIME);
memcpy(&dataGps, pBuffer+nPos,sizeof(RMBDM_GPS));
nPos += sizeof(RMBDM_GPS);
NSString*time=[NSStringstringWithFormat:@"%d-%d-%d %d:%d:%d",dataTime.stuDateTime.cYear,dataTime.stuDateTime.cMonth,dataTime.stuDateTime.cDay,dataTime.stuDateTime.cHour,dataTime.stuDateTime.cMinute,dataTime.stuDateTime.cSecond];
N9MRmdbGpsInfo* rmdbGpsInfo=[[N9MRmdbGpsInfoalloc]init];
rmdbGpsInfo.cVersion=[NSStringstringWithFormat:@"%d",dataGps.cVersion];
rmdbGpsInfo.cGpsSource=[NSStringstringWithFormat:@"%d",dataGps.cGpsSource];
rmdbGpsInfo.reserved1=[NSStringstringWithFormat:@"%d",dataGps.reserved1];
rmdbGpsInfo.cGpsStatus=[NSStringstringWithFormat:@"%d",dataGps.cGpsStatus];
rmdbGpsInfo.cSpeedUnit=[NSStringstringWithFormat:@"%d",dataGps.cSpeedUnit];
rmdbGpsInfo.usSpeed=dataGps.usSpeed;
rmdbGpsInfo.cDirectionLatitude=[NSStringstringWithFormat:@"%d",dataGps.cDirectionLatitude];
rmdbGpsInfo.cDirectionLongitude=[NSStringstringWithFormat:@"%d",dataGps.cDirectionLongitude];
rmdbGpsInfo.cLongitudeCent=[NSStringstringWithFormat:@"%d",dataGps.cLongitudeCent];
rmdbGpsInfo.lLatitudeSec=dataGps.lLatitudeSec;
rmdbGpsInfo.lLongitudeSec=dataGps.lLongitudeSec;
rmdbGpsInfo.usGpsAngle=dataGps.usGpsAngle;
rmdbGpsInfo.cGpPlanetNum=[NSStringstringWithFormat:@"%d",dataGps.cGpPlanetNum];
rmdbGpsInfo.cBdPlanetNum=[NSStringstringWithFormat:@"%d",dataGps.cBdPlanetNum];
rmdbGpsInfo.cSignalStrength=[NSStringstringWithFormat:@"%d",dataGps.cSignalStrength];
[dataDic setObject:rmdbGpsInfoforKey:time];
}