本地数据存储与读取V0.5

存储位置

沙盒SandBox


app安装后,系统会为其创建一个根目录,用来写入应用的数据或者首选项参数,这个根目录就是应用程序的沙盒.
获取沙盒目录
NSString *homeDirectory = NSHomeDirectory();
或者
NSString *userName = NSUserName();
NSString * homeDirectory = NSHomeDirectoryForUser(userName);
结果是一样的
/var/mobile/Containers/Data/Application/BD2819B1-5873-4A4F-8375-EE0CA8E6YFHG

沙盒下子目录


AppName.app

存放应用程序自身

Documents

存放用户文档和应用数据文件(自动备份)
获取目录
NSString *dpath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];

Library

应用程序规范的顶级目录,下面有一些规范定义的的子目录,当然也可以自定义子目录,用于存放应用的文件,但是不宜存放用户数据文件,和document一样会被itunes同步,但不包括caches子目录.
Library/Preferences:这里存放程序规范要求的首选项文件,包含应用程序的偏好设置文件.您不应该直接创建偏好设置文件,而是应该使用NSUserDefaults类来取得和设置应用程序的偏好.(自动备份)
获取Library目录:
NSString *lpath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
Library/Caches:保存应用的持久化数据,用于应用升级或者应用关闭后的数据保存,不会被itunes同步,所以为了减少同步的时间,可以考虑将一些比较大的文件而又不需要备份的文件放到这个目录下(不删除,不备份)
获取Library/Caches目录:
NSString *cpath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];

Tmp

存放临时文件,在应用关闭后,该目录下的数据将删除,也可能系统在程序不运行的时候清除.(随时删除)
NSString *tpath = NSTemporaryDirectory();

PS: --------------------------------------


NSSearchPathForDirectoriesInDomains路径获取函数详解:
FOUNDATION_EXPORT NSArray *NSSearchPathForDirectoriesInDomains(
NSSearchPathDirectory directory, 
NSSearchPathDomainMask domainMask, 
BOOL expandTilde);

该方法用于返回指定范围内的指定名称的目录的路径集合。有三个参数:

directory:NSSearchPathDirectory类型的enum值,表明我们要搜索的目录名称,比如这里用NSDocumentDirectory表明我们要搜索的是Documents目录.如果我们将其换成NSCachesDirectory就表示我们搜索的是Library/Caches目录.

typedef NS_ENUM(NSUInteger, NSSearchPathDirectory) {
    NSApplicationDirectory = 1,             // supported applications (Applications)
    NSDemoApplicationDirectory,             // unsupported applications, demonstration versions (Demos)
    NSDeveloperApplicationDirectory,        // developer applications (Developer/Applications). DEPRECATED - there is no one single Developer directory.
    NSAdminApplicationDirectory,            // system and network administration applications (Administration)
    NSLibraryDirectory,                     // various documentation, support, and configuration files, resources (Library)
    NSDeveloperDirectory,                   // developer resources (Developer) DEPRECATED - there is no one single Developer directory.
    NSUserDirectory,                        // user home directories (Users)
    NSDocumentationDirectory,               // documentation (Documentation)
    NSDocumentDirectory,                    // documents (Documents)
    NSCoreServiceDirectory,                 // location of CoreServices directory (System/Library/CoreServices)
    NSAutosavedInformationDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 11,   // location of autosaved documents (Documents/Autosaved)
    NSDesktopDirectory = 12,                // location of user's desktop
    NSCachesDirectory = 13,                 // location of discardable cache files (Library/Caches)
    NSApplicationSupportDirectory = 14,     // location of application support files (plug-ins, etc) (Library/Application Support)
    NSDownloadsDirectory NS_ENUM_AVAILABLE(10_5, 2_0) = 15,              // location of the user's "Downloads" directory
    NSInputMethodsDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 16,           // input methods (Library/Input Methods)
    NSMoviesDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 17,                 // location of user's Movies directory (~/Movies)
    NSMusicDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 18,                  // location of user's Music directory (~/Music)
    NSPicturesDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 19,               // location of user's Pictures directory (~/Pictures)
    NSPrinterDescriptionDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 20,     // location of system's PPDs directory (Library/Printers/PPDs)
    NSSharedPublicDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 21,           // location of user's Public sharing directory (~/Public)
    NSPreferencePanesDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 22,        // location of the PreferencePanes directory for use with System Preferences (Library/PreferencePanes)
    NSApplicationScriptsDirectory NS_ENUM_AVAILABLE(10_8, NA) = 23,      // location of the user scripts folder for the calling application (~/Library/Application Scripts/code-signing-id)
    NSItemReplacementDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 99,       // For use with NSFileManager's URLForDirectory:inDomain:appropriateForURL:create:error:
    NSAllApplicationsDirectory = 100,       // all directories where applications can occur
    NSAllLibrariesDirectory = 101,          // all directories where resources can occur
    NSTrashDirectory NS_ENUM_AVAILABLE(10_8, NA) = 102                   // location of Trash directory
};

其中:
NSDocumentDirectory是指程序中对应的Documents路径。
NSDocumentionDirectory对应于程序中的Library/Documentation路径,这个路径是没有读写权限的,所以看不到文件生成。

** domain:**是MaskNSSearchPathDomainMask类型的enum值,指定搜索范围,这里的NSUserDomainMask表示搜索的范围限制于当前应用的沙盒目录.还可以写成NSLocalDomainMask(表示/Library)、NSNetworkDomainMask(表示/Network)等.

typedef NS_OPTIONS(NSUInteger, NSSearchPathDomainMask) {
    NSUserDomainMask = 1,       // user's home directory --- place to install user's personal items (~)
    NSLocalDomainMask = 2,      // local to the current machine --- place to install items available to everyone on this machine (/Library)
    NSNetworkDomainMask = 4,    // publically available location in the local area network --- place to install items available on the network (/Network)
    NSSystemDomainMask = 8,     // provided by Apple, unmodifiable (/System)
    NSAllDomainsMask = 0x0ffff  // all domains: all of the above and future items
};

expandTilde:BOOL值,表示是否展开波浪线。我们知道在iOS中的全写形式是/User/userName,该值为YES即表示写成全写形式,为NO就表示直接写成“~”。

资源目录
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:filename];
NSString *path = [[NSBundle mainBundle] resourcePath];
NSString *path = [[NSBundle mainBundle] pathForResource: @"info" ofType: @"txt"];

存储方法

1.NSKeyedArchiver


归档保存数据,该数据对象需要遵守NSCoding协议,并且该对象对应的类必须提供encodeWithCoder:initWithCoder:方法。前⼀个方法告诉系统怎么将对象编码,而后⼀个方法是告诉系统怎么将对象解码。

//例如对Possession对象归档保存。
//定义Possession:
@interface Possession:NSObject //遵守NSCoding协议
{
    NSString *name;//待归档类型 
}
@implementation Possession 
-(void)encodeWithCoder:(NSCoder *)aCoder{
    [aCoder encodeObject:name forKey:@"name"]; 
}
-(void)initWithCoder:(NSCoder *)aDecoder{
    name=[[aDeCoder decodeObjectforKey:@"name"] retain];
}

归档操作:
如果对Possession对象allPossession归档保存,只需使用NSCoder子类NSKeyedArchiver的方法 archiveRootObject:toFile:,返回值flag为YES表示序列化成功反之失败。
NSString *path = [self possessionArchivePath]; BOOL flag = [NSKeyedArchiver archiveRootObject:allPossessions toFile: path ];

解压操作:
同样调用NSCoder子类NSKeyedArchiver的方法unarchiveRootObject:toFile:即可。
allPossessions = [[NSKeyedUnarchiver unarchiveObjectWithFile:path] retain];

缺点:归档的形式来保存数据,只能一次性归档保存以及⼀次性解压。所以只能针对小量数据,而且对数据操作比较 笨拙,即如果想改动数据的某一小部分,还是需要解压整个数据或者归档整个数据。
补充:关于结构体的序列化

2.NSUserDefaults


NSUserDefaults是单例,同时也是线程安全的,操作方法几乎与NSDictionary的操作方法无异, 用来保存应用程序设置和属性、用户保存的数据。
用户再次打开程序或开机后这些数据仍然存在,数据以plist格式归档在相应应用目录的Library/Preferences下。
NSUserDefaults会把全部的数据都载入到内存,而且之后常驻内存,所以操作速度很快,但大规模数据不适合用NSUserDefaults。

NSUserDefaults可以存储的数据类型包括:
NSDataNSStringNSNumberNSDateNSArrayNSDictionary
如果要存储其他类型,则需要转换为前面的类型,才能用NSUserDefaults存储。

实例1.简单的存取NSString 、NSData
//保存NSString 、NSData
NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults]; 
NSString *name =@"xiao ming";
[defaults setObject:name forKey:@"name"];
UIImage *image=[[UIImage alloc]initWithContentsOfFile:@"photo.jpg"];
NSData *imageData = UIImageJPEGRepresentation(image, 100); 
[defaults setObject:imageData forKey:@"image"]; 
//这句不写的话也会自动执行
[defaults synchronize];
//读取NSString 、NSData
NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults];
//根据键值取出name
NSString *name = [defaults objectForKey:@"name"];
NSData *imageData = [defaults dataForKey:@"image"];
//NSData转换为UIImage
UIImage *Image = [UIImage imageWithData:imageData];
实例2.将自定义类型数据存入NSUserDefaults

1.存储全班同学的信息
我们可以建一个NSMutableArray* studentArr来存放全班同学的信息(里面存储的全是模型Student对象).
需要存储的时候可以建一个NSMutableArray * dataArray把每一个模型专转成data 添加到数组,然后存入NSUserDefaults

//首先,要建立一个可变数组来存储 NSData对象
Student *student = [[Student alloc] ini];
//下面进行的是对student对象的 name , studentNumber ,sex 的赋值
student.name = @"lady-奕奕";
student.studentNumber = @"3100104006";
student.sex = @"女";
//这是一个存放全班同学的数组
NSMutableArray * dataArray = [NSMutableArray arrayWithCapacity:50];
//将student类型变为NSData类型
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:student];
//存放数据的数组将data加入进去
[dataArray addObject:data];
//存一个人的信息,直接将NSData存入NSUserDefaults中 :
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:student];   
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:data forKey:@"oneStudent"];
//存储全班同学的信息,用一个for循环将data 放入 dataArray中:
for (Student *student in studentArr){
   NSData *data = [NSKeyedArchiver archivedDataWithRootObject:student];
   [dataArray addObject:data];
}
//记住要转换成不可变数组类型
NSArray * array = [NSArray arrayWithArray:dataArray];
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:array forKey:@"allStudent"];

2.从NSUserDefaults中取出数据在还原

//还原一个学生的数据: 
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
NSdData *data = [user objectForKey:@"oneStudent"];
Student *student = [NSKeyedUnarchiver unarchiveObjectWithData:data];
//还原全部学生数据
NSUserDefaults * user = [NSUserDefaults standardUserDefaults];
NSArray * array = [defaults objectForKey:@"allStudent"];
NSMutableArray *temArr = [[NSMutableArray alloc] init];
for (NSData * data in array){
   [temArr addObject:[NSKeyedUnarchiver unarchiveObjectWithData: data]];
}

3. Write写入


永久保存在磁盘中。具体方法为:
第一步:获得文件即将保存的路径:
NSString *dpath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];

还有一种方法是使用NSHomeDirectory函数获得sandbox的路径。具体的用法为:
NSString *sPath = NSHomeDirectory();
NSString *dpath = [sPath stringByAppendingPathComponent:@"Documents"];

两者的区别:使用NSSearchPathForDirectoriesInDomains比在NSHomeDirectory后面添加Document更加安全。因为该文件目录可能在未来发送的系统上发生改变。

第二步:生成在该路径下的文件:
假如文件名叫:hahaha.plist
NSString *filename=[dpath stringByAppendingPathComponent:@"hahaha.plist"];

第三步:往文件中写入数据:
//将NSData类型对象data写入文件,文件名为filename
[data writeToFile: filename atomically:YES];

最后:从文件中读出数据:
NSData data=[NSData dataWithContentsOfFile: filename options:0 error:NULL];

4. SQLite


采用SQLite数据库来存储数据。SQLite作为⼀一中小型数据库,应用iOS中,跟前三种保存方式相比,相对复杂一些。

原生sqlite使用
  • 需要添加SQLite相关的库以及头文件

在项目文件的Build Phases下,找到Link Binary Libraryies,
添加libsqlite3.0.dylib
在项目文件中头文件或者源文件中添加头文件
#import "sqlite3.h"

关于libsqlite3.0.dylib和libsqlite3.dylib
libsqlite3.0.dylib本身是个链接,它指向libsqlite3.dylib。
在项目里添加libsqlite3.dylib或添加libsqlite3.0.dylib其实是添加了同一个文件。
libsqlite3.0.dylib总是指向最新的sqlite3动态库
比如说sqlite3库更新了,如果我们引用的是libsqlite3.0.dylib你就不需要做任何修改了。
  • 开始使用SQLite

使用前注意:如果不往数据库里面添加任何的表,这个数据库等于没有建立,不会在硬盘上产生任何文件,如果数据库已经存在,则会打开这个数据库。

//dpath 是目录里面讲过的document 目录
NSString *dbpath=[dpath stringByAppendingPathComponent:@"mydb"];
//打开数据库
if (sqlite3_open([dbpath UTF8String], &_db)==SQLITE_OK) {
    NSLog(@"sqlite dadabase is opened."); 
}else{ return;}//打开不成功就返回


-(BOOL)openDB{
    BOOL result = NO;
    if (sqlite3_open([[self dbPath] UTF8String], &_db)==SQLITE_OK) {
        result = YES;
        NSLog(@"sqlite database is opended");
    }else{
        NSLog(@"sqlte database open faile");
        result = NO;
    }
    return result;
}

建表:

char *error;
const char *createSql="CREATE TABLE IF NOT EXISTS table_name
(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)";

if (sqlite3_exec(_db, createSql, NULL, NULL, &error)==SQLITE_OK) {
    NSLog(@"create table is ok."); 
}else {
NSLog(@"error:%s",error);
sqlite3_free(error);//每次使用完毕清空error字符串,提供给下⼀一次使用 
}

插入:

const char *insertSql="INSERT INTO table_name
('name','id') VALUES('WANGWU','210')";
if (sqlite3_exec(database, insertSql, NULL, NULL, &error)==SQLITE_OK) {
    NSLog(@"insert operation is ok.");
}else {
    NSLog(@"error: %s",error);
    sqlite3_free(error);//每次使用完毕清空error字符串,提供给下⼀一次使用
}

查询:

const char *selectSql="select id,name from a person";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database,selectSql, -1, &statement, nil)==SQLITE_OK) { 
    NSLog(@"select operation is ok."); 
}else {
    sqlite3_free(error); 
}
while(sqlite3_step(statement)==SQLITE_ROW) {
    int _id=sqlite3_column_int(statement, 0);
    NSString *name=(char*)sqlite3_column_text(statement, 1);
     NSLog(@"row>>id %i, name %s",_id,name);
}
sqlite3_finalize(statement);

PS----------------------------------------

int sqlite3_prepare_v2(
//数据指针
  sqlite3 *db,            
//sql语句,使用UTF-8编码
  const char *zSql,      
/*如果nByte小于0,则函数取出zSql中从开始到第一个0终止符的内容;
 *如果nByte不是负的,那么它就是这个函数能从zSql中读取的字节数的最大值。
 */
  int nByte,            
/*能够使用sqlite3_step()执行的 编译好的 准备语句的 指针 
*如果错误发生 它被置为NULL 如假如输入的文本不包括sql语句。
*调用过程必须负责在编译好的sql语句完成使用后使用sqlite3_finalize()删除它。
*/
  sqlite3_stmt **ppStmt,  
/*zSql在遇见终止符或者是达到设定的nByte之后结束 
假如zSql还有剩余的内容 那么这些剩余的内容被存放到pZTail中 不包括终止符
*/
  const char **pzTail     
);
说明
如果执行成功,则返回SQLITE_OK,否则返回一个错误码。
推荐在现在任何的程序中都使用sqlite3_prepare_v2这个函数,
sqlite3_prepare只是用于前向兼容

sqlite3_prepare_v2详情查看

最后,关闭数据库:
sqlite3_close(database);
注意:写入数据库,字符串可以采用char方式,而从数据库中取出char类型,当char类型有表示中文字符 时,会出现乱码。
这是因为数据库默认使用ascII编码方式。所以要想正确从数据库中取出中文,需要用 NSString来接收从数据库取出的字符串。
如果引入第三方库会变得简单很多 比如FMDB。

读取


1.读取工程内的JSON文件

<code>
NSString *path = [[NSBundle mainBundle] pathForResource:@"products.json" ofType:nil];// JSON文件的路径
NSData *data = [NSData dataWithContentsOfFile:path]; // 加载JSON文件
NSArray *dictArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];// 将JSON数据转为NSArray或者NSDictionary
</code>

http://www.cocoachina.com/industry/20130328/5908.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 沙盒 Plist Preference偏好设置 NSKeyedArchiver归档 / NSKeyedUnarch...
    追风者366阅读 3,333评论 0 6
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,134评论 30 470
  • 前言 iOS本地缓存数据方式有五种: 1.直接写文件方式*.plist:可以存储的对象有NSString、NSAr...
    随心吧阅读 1,981评论 0 18
  • 1,依赖包安装 rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/i...
    严国华阅读 1,214评论 0 0
  • 概括:释迦摩尼说,无论你遇见谁,他都是你生命中该出现的人,绝非偶然。他一定教会你什么,然后再离去。所以好好对待你生...
    他她他们阅读 285评论 0 1