存储位置
沙盒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
可以存储的数据类型包括:
NSData
、NSString
、NSNumber
、NSDate
、NSArray
、 NSDictionary
。
如果要存储其他类型,则需要转换为前面的类型,才能用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_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>