IOS 读二进制数据文件
IOS 讀二進制數(shù)據(jù)文件
在開發(fā)項目的過程中,我們有可能遇到上面這圖片展示的數(shù)據(jù)。其實這些數(shù)據(jù)是存放到文件中的二進制數(shù)據(jù)。記得大學的時候老師帶著我們寫了一個記賬類軟件,當時就是把賬單里面的數(shù)據(jù)存放到文件里面。我直接簡述那時候是怎么做的。首先得有個賬單類。
------------------賬單類的頭文件-----------------
//
//? 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>協(xié)議。為什么要實現(xiàn)此協(xié)議呢?因為我們數(shù)據(jù)寫到文件中,其事就是一個拷貝的過程,需要進行。我們要拷貝一份數(shù)據(jù),拷貝后的兩份數(shù)據(jù)互相不影響,是一份獨立的克隆體,修改一份中的數(shù)據(jù)時另一份中的數(shù)據(jù)不會相互影響。這就需要實現(xiàn)<NSCopying>協(xié)議: -( id )copyWithZone:( NSZone ?*)zone方法或<NSMutableCopying>協(xié)議的:- (id)mutableCopyWithZone:(NSZone?*)zone。接下來就是要把數(shù)據(jù)寫在文件中,存放到該應(yīng)用程序沙盒里面。首先得有個路徑來存放數(shù)據(jù),獲取路徑的方法如下。
#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//寫的函數(shù)
{
? ??NSMutableData*data=[[NSMutableDataalloc]init];//聲明一個可變數(shù)據(jù)類型
? ??NSKeyedArchiver*archiver=[[NSKeyedArchiveralloc]initForWritingWithMutableData:data];//編碼
? ? [archiver?encodeObject:listforKey:KDataKey];//存放數(shù)據(jù)文件的類型和名字
? ? [archiver?finishEncoding];//編碼完成
? ? [data?writeToFile:[selfdataFilepath]atomically:YES];//寫在相應(yīng)的路徑下
}
-(NSMutableArray?*) readListFromFile:(NSString?*) fileName//讀的函數(shù)
{
? ??if?([[NSFileManagerdefaultManager]fileExistsAtPath:fileName])//是否存在要讀的數(shù)據(jù)類型,如果存在
? ? {
? ? ? ??NSData*data=[[NSMutableDataalloc]initWithContentsOfFile:fileName];//打開名為fileName數(shù)據(jù)類型的數(shù)據(jù)
?? ? ??NSKeyedUnarchiver*unarchiver=[[NSKeyedUnarchiveralloc]initForReadingWithData:data];//解碼
? ? ? ??NSMutableArray?* array = [unarchiverdecodeObjectForKey:KDataKey];//把解碼出來的數(shù)據(jù)存放在可變數(shù)組里面
? ? ? ? [unarchiver?finishDecoding];//解碼完成
? ? ? ??if?(!array) {
? ? ? ? ? ? array=[[NSMutableArrayalloc]init];
? ? ? ? }
? ? ? ??return?array;//返回該數(shù)組
? ? }
?? ?
? ??return?[[NSMutableArrayalloc]init];;//如果不存在名為fileName數(shù)據(jù)類型直接返回空
}
可以看出這種把數(shù)據(jù)寫到文件中,其實就是利用NSKeyedArchiver歸檔(將各種類型的對象存到文件中) ,編碼后直接調(diào)用- (BOOL)writeToFile:(NSString?*)path atomically:(BOOL)useAuxiliaryFile;寫到文件中就可以了。讀出來的時候也是調(diào)用相應(yīng)的函數(shù)讀出來,然后解碼。這個存進去的數(shù)據(jù)就可以完全讀出來了。寫到這里,可能大家會認為關(guān)于文件的讀寫就完了。其實今天的重點還沒有開始。
我們在iOS中NSKeyedArchiver方法來歸檔數(shù)據(jù)。數(shù)據(jù)的讀寫相對容易得多了。有時候我們拿到的文件是其它平臺把一個已經(jīng)定義好了的結(jié)構(gòu)體等數(shù)據(jù)以二進制的方式存放到文件中。問題就來了這時候怎么讀數(shù)據(jù)呢?其實這時候我們就要用到下面的方法來對數(shù)據(jù)進行讀的操作。這些數(shù)據(jù)存儲空間里面是有相應(yīng)的長度的,我們知道了該結(jié)構(gòu)體的定義,就可以知道該結(jié)構(gòu)體的長度,然后就可以把這些數(shù)據(jù)一個字節(jié)一個字節(jié)的拷貝出來。這需要我們iOS端有與之相應(yīng)的結(jié)構(gòu)體。下面這段代碼就是對一份文件中存了很多個相同結(jié)構(gòu)的結(jié)構(gòu)數(shù)據(jù)拷貝出來。大概思想就是我們做了一個循環(huán)來讀每一個結(jié)構(gòu)體的數(shù)據(jù),只要拷貝的總字節(jié)小于文件的總字節(jié)數(shù)。就說明這個數(shù)據(jù)還沒有讀到末尾。還用了一個變量來紀錄目前讀過的總字節(jié)數(shù)。具體代碼如下。
NSString?*path = [[NSBundlemain Bundle]pathForResource:@"n9gps"ofType:@"rbb"];
//獲取數(shù)據(jù)
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];
}
總結(jié)
以上是生活随笔為你收集整理的IOS 读二进制数据文件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 杰洛特的Python之旅01_抓取微信性
- 下一篇: VMware收购云监控公司Wavefro