本地?cái)?shù)據(jù)存儲(chǔ)與讀取V0.5

存儲(chǔ)位置

沙盒SandBox


app安裝后,系統(tǒng)會(huì)為其創(chuàng)建一個(gè)根目錄,用來(lái)寫(xiě)入應(yīng)用的數(shù)據(jù)或者首選項(xiàng)參數(shù),這個(gè)根目錄就是應(yīng)用程序的沙盒.
獲取沙盒目錄
NSString *homeDirectory = NSHomeDirectory();
或者
NSString *userName = NSUserName();
NSString * homeDirectory = NSHomeDirectoryForUser(userName);
結(jié)果是一樣的
/var/mobile/Containers/Data/Application/BD2819B1-5873-4A4F-8375-EE0CA8E6YFHG

沙盒下子目錄


AppName.app

存放應(yīng)用程序自身

Documents

存放用戶(hù)文檔和應(yīng)用數(shù)據(jù)文件(自動(dòng)備份)
獲取目錄
NSString *dpath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];

Library

應(yīng)用程序規(guī)范的頂級(jí)目錄,下面有一些規(guī)范定義的的子目錄,當(dāng)然也可以自定義子目錄,用于存放應(yīng)用的文件,但是不宜存放用戶(hù)數(shù)據(jù)文件,和document一樣會(huì)被itunes同步,但不包括caches子目錄.
Library/Preferences:這里存放程序規(guī)范要求的首選項(xiàng)文件,包含應(yīng)用程序的偏好設(shè)置文件.您不應(yīng)該直接創(chuàng)建偏好設(shè)置文件,而是應(yīng)該使用NSUserDefaults類(lèi)來(lái)取得和設(shè)置應(yīng)用程序的偏好.(自動(dòng)備份)
獲取Library目錄:
NSString *lpath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
Library/Caches:保存應(yīng)用的持久化數(shù)據(jù),用于應(yīng)用升級(jí)或者應(yīng)用關(guān)閉后的數(shù)據(jù)保存,不會(huì)被itunes同步,所以為了減少同步的時(shí)間,可以考慮將一些比較大的文件而又不需要備份的文件放到這個(gè)目錄下(不刪除,不備份)
獲取Library/Caches目錄:
NSString *cpath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];

Tmp

存放臨時(shí)文件,在應(yīng)用關(guān)閉后,該目錄下的數(shù)據(jù)將刪除,也可能系統(tǒng)在程序不運(yùn)行的時(shí)候清除.(隨時(shí)刪除)
NSString *tpath = NSTemporaryDirectory();

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


NSSearchPathForDirectoriesInDomains路徑獲取函數(shù)詳解:
FOUNDATION_EXPORT NSArray *NSSearchPathForDirectoriesInDomains(
NSSearchPathDirectory directory, 
NSSearchPathDomainMask domainMask, 
BOOL expandTilde);

該方法用于返回指定范圍內(nèi)的指定名稱(chēng)的目錄的路徑集合。有三個(gè)參數(shù):

directory:NSSearchPathDirectory類(lèi)型的enum值,表明我們要搜索的目錄名稱(chēng),比如這里用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是指程序中對(duì)應(yīng)的Documents路徑。
NSDocumentionDirectory對(duì)應(yīng)于程序中的Library/Documentation路徑,這個(gè)路徑是沒(méi)有讀寫(xiě)權(quán)限的,所以看不到文件生成。

** domain:**是MaskNSSearchPathDomainMask類(lèi)型的enum值,指定搜索范圍,這里的NSUserDomainMask表示搜索的范圍限制于當(dāng)前應(yīng)用的沙盒目錄.還可以寫(xiě)成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值,表示是否展開(kāi)波浪線。我們知道在iOS中的全寫(xiě)形式是/User/userName,該值為YES即表示寫(xiě)成全寫(xiě)形式,為NO就表示直接寫(xiě)成“~”。

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

存儲(chǔ)方法

1.NSKeyedArchiver


歸檔保存數(shù)據(jù),該數(shù)據(jù)對(duì)象需要遵守NSCoding協(xié)議,并且該對(duì)象對(duì)應(yīng)的類(lèi)必須提供encodeWithCoder:initWithCoder:方法。前?個(gè)方法告訴系統(tǒng)怎么將對(duì)象編碼,而后?個(gè)方法是告訴系統(tǒng)怎么將對(duì)象解碼。

//例如對(duì)Possession對(duì)象歸檔保存。
//定義Possession:
@interface Possession:NSObject //遵守NSCoding協(xié)議
{
    NSString *name;//待歸檔類(lèi)型 
}
@implementation Possession 
-(void)encodeWithCoder:(NSCoder *)aCoder{
    [aCoder encodeObject:name forKey:@"name"]; 
}
-(void)initWithCoder:(NSCoder *)aDecoder{
    name=[[aDeCoder decodeObjectforKey:@"name"] retain];
}

歸檔操作:
如果對(duì)Possession對(duì)象allPossession歸檔保存,只需使用NSCoder子類(lèi)NSKeyedArchiver的方法 archiveRootObject:toFile:,返回值flag為YES表示序列化成功反之失敗。
NSString *path = [self possessionArchivePath]; BOOL flag = [NSKeyedArchiver archiveRootObject:allPossessions toFile: path ];

解壓操作:
同樣調(diào)用NSCoder子類(lèi)NSKeyedArchiver的方法unarchiveRootObject:toFile:即可。
allPossessions = [[NSKeyedUnarchiver unarchiveObjectWithFile:path] retain];

缺點(diǎn):歸檔的形式來(lái)保存數(shù)據(jù),只能一次性歸檔保存以及?次性解壓。所以只能針對(duì)小量數(shù)據(jù),而且對(duì)數(shù)據(jù)操作比較 笨拙,即如果想改動(dòng)數(shù)據(jù)的某一小部分,還是需要解壓整個(gè)數(shù)據(jù)或者歸檔整個(gè)數(shù)據(jù)。
補(bǔ)充:關(guān)于結(jié)構(gòu)體的序列化

2.NSUserDefaults


NSUserDefaults是單例,同時(shí)也是線程安全的,操作方法幾乎與NSDictionary的操作方法無(wú)異, 用來(lái)保存應(yīng)用程序設(shè)置和屬性、用戶(hù)保存的數(shù)據(jù)。
用戶(hù)再次打開(kāi)程序或開(kāi)機(jī)后這些數(shù)據(jù)仍然存在,數(shù)據(jù)以plist格式歸檔在相應(yīng)應(yīng)用目錄的Library/Preferences下。
NSUserDefaults會(huì)把全部的數(shù)據(jù)都載入到內(nèi)存,而且之后常駐內(nèi)存,所以操作速度很快,但大規(guī)模數(shù)據(jù)不適合用NSUserDefaults。

NSUserDefaults可以存儲(chǔ)的數(shù)據(jù)類(lèi)型包括:
NSData、NSStringNSNumber、NSDate、NSArray、 NSDictionary。
如果要存儲(chǔ)其他類(lèi)型,則需要轉(zhuǎn)換為前面的類(lèi)型,才能用NSUserDefaults存儲(chǔ)。

實(shí)例1.簡(jiǎn)單的存取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"]; 
//這句不寫(xiě)的話也會(huì)自動(dòng)執(zhí)行
[defaults synchronize];
//讀取NSString 、NSData
NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults];
//根據(jù)鍵值取出name
NSString *name = [defaults objectForKey:@"name"];
NSData *imageData = [defaults dataForKey:@"image"];
//NSData轉(zhuǎn)換為UIImage
UIImage *Image = [UIImage imageWithData:imageData];
實(shí)例2.將自定義類(lèi)型數(shù)據(jù)存入NSUserDefaults

1.存儲(chǔ)全班同學(xué)的信息
我們可以建一個(gè)NSMutableArray* studentArr來(lái)存放全班同學(xué)的信息(里面存儲(chǔ)的全是模型Student對(duì)象).
需要存儲(chǔ)的時(shí)候可以建一個(gè)NSMutableArray * dataArray把每一個(gè)模型專(zhuān)轉(zhuǎn)成data 添加到數(shù)組,然后存入NSUserDefaults。

//首先,要建立一個(gè)可變數(shù)組來(lái)存儲(chǔ) NSData對(duì)象
Student *student = [[Student alloc] ini];
//下面進(jìn)行的是對(duì)student對(duì)象的 name , studentNumber ,sex 的賦值
student.name = @"lady-奕奕";
student.studentNumber = @"3100104006";
student.sex = @"女";
//這是一個(gè)存放全班同學(xué)的數(shù)組
NSMutableArray * dataArray = [NSMutableArray arrayWithCapacity:50];
//將student類(lèi)型變?yōu)镹SData類(lèi)型
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:student];
//存放數(shù)據(jù)的數(shù)組將data加入進(jìn)去
[dataArray addObject:data];
//存一個(gè)人的信息,直接將NSData存入NSUserDefaults中 :
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:student];   
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:data forKey:@"oneStudent"];
//存儲(chǔ)全班同學(xué)的信息,用一個(gè)for循環(huán)將data 放入 dataArray中:
for (Student *student in studentArr){
   NSData *data = [NSKeyedArchiver archivedDataWithRootObject:student];
   [dataArray addObject:data];
}
//記住要轉(zhuǎn)換成不可變數(shù)組類(lèi)型
NSArray * array = [NSArray arrayWithArray:dataArray];
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:array forKey:@"allStudent"];

2.從NSUserDefaults中取出數(shù)據(jù)在還原

//還原一個(gè)學(xué)生的數(shù)據(jù): 
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
NSdData *data = [user objectForKey:@"oneStudent"];
Student *student = [NSKeyedUnarchiver unarchiveObjectWithData:data];
//還原全部學(xué)生數(shù)據(jù)
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寫(xiě)入


永久保存在磁盤(pán)中。具體方法為:
第一步:獲得文件即將保存的路徑:
NSString *dpath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];

還有一種方法是使用NSHomeDirectory函數(shù)獲得sandbox的路徑。具體的用法為:
NSString *sPath = NSHomeDirectory();
NSString *dpath = [sPath stringByAppendingPathComponent:@"Documents"];

兩者的區(qū)別:使用NSSearchPathForDirectoriesInDomains比在NSHomeDirectory后面添加Document更加安全。因?yàn)樵撐募夸浛赡茉谖磥?lái)發(fā)送的系統(tǒng)上發(fā)生改變。

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

第三步:往文件中寫(xiě)入數(shù)據(jù):
//將NSData類(lèi)型對(duì)象data寫(xiě)入文件,文件名為filename
[data writeToFile: filename atomically:YES];

最后:從文件中讀出數(shù)據(jù):
NSData data=[NSData dataWithContentsOfFile: filename options:0 error:NULL];

4. SQLite


采用SQLite數(shù)據(jù)庫(kù)來(lái)存儲(chǔ)數(shù)據(jù)。SQLite作為?一中小型數(shù)據(jù)庫(kù),應(yīng)用iOS中,跟前三種保存方式相比,相對(duì)復(fù)雜一些。

原生sqlite使用
  • 需要添加SQLite相關(guān)的庫(kù)以及頭文件

在項(xiàng)目文件的Build Phases下,找到Link Binary Libraryies,
添加libsqlite3.0.dylib。
在項(xiàng)目文件中頭文件或者源文件中添加頭文件
#import "sqlite3.h"

關(guān)于libsqlite3.0.dylib和libsqlite3.dylib
libsqlite3.0.dylib本身是個(gè)鏈接,它指向libsqlite3.dylib。
在項(xiàng)目里添加libsqlite3.dylib或添加libsqlite3.0.dylib其實(shí)是添加了同一個(gè)文件。
libsqlite3.0.dylib總是指向最新的sqlite3動(dòng)態(tài)庫(kù)
比如說(shuō)sqlite3庫(kù)更新了,如果我們引用的是libsqlite3.0.dylib你就不需要做任何修改了。
  • 開(kāi)始使用SQLite

使用前注意:如果不往數(shù)據(jù)庫(kù)里面添加任何的表,這個(gè)數(shù)據(jù)庫(kù)等于沒(méi)有建立,不會(huì)在硬盤(pán)上產(chǎn)生任何文件,如果數(shù)據(jù)庫(kù)已經(jīng)存在,則會(huì)打開(kāi)這個(gè)數(shù)據(jù)庫(kù)。

//dpath 是目錄里面講過(guò)的document 目錄
NSString *dbpath=[dpath stringByAppendingPathComponent:@"mydb"];
//打開(kāi)數(shù)據(jù)庫(kù)
if (sqlite3_open([dbpath UTF8String], &_db)==SQLITE_OK) {
    NSLog(@"sqlite dadabase is opened."); 
}else{ return;}//打開(kāi)不成功就返回


-(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字符串,提供給下?一次使用
}

查詢(xún):

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(
//數(shù)據(jù)指針
  sqlite3 *db,            
//sql語(yǔ)句,使用UTF-8編碼
  const char *zSql,      
/*如果nByte小于0,則函數(shù)取出zSql中從開(kāi)始到第一個(gè)0終止符的內(nèi)容;
 *如果nByte不是負(fù)的,那么它就是這個(gè)函數(shù)能從zSql中讀取的字節(jié)數(shù)的最大值。
 */
  int nByte,            
/*能夠使用sqlite3_step()執(zhí)行的 編譯好的 準(zhǔn)備語(yǔ)句的 指針 
*如果錯(cuò)誤發(fā)生 它被置為NULL 如假如輸入的文本不包括sql語(yǔ)句。
*調(diào)用過(guò)程必須負(fù)責(zé)在編譯好的sql語(yǔ)句完成使用后使用sqlite3_finalize()刪除它。
*/
  sqlite3_stmt **ppStmt,  
/*zSql在遇見(jiàn)終止符或者是達(dá)到設(shè)定的nByte之后結(jié)束 
假如zSql還有剩余的內(nèi)容 那么這些剩余的內(nèi)容被存放到pZTail中 不包括終止符
*/
  const char **pzTail     
);
說(shuō)明
如果執(zhí)行成功,則返回SQLITE_OK,否則返回一個(gè)錯(cuò)誤碼。
推薦在現(xiàn)在任何的程序中都使用sqlite3_prepare_v2這個(gè)函數(shù),
sqlite3_prepare只是用于前向兼容

sqlite3_prepare_v2詳情查看

最后,關(guān)閉數(shù)據(jù)庫(kù):
sqlite3_close(database);
注意:寫(xiě)入數(shù)據(jù)庫(kù),字符串可以采用char方式,而從數(shù)據(jù)庫(kù)中取出char類(lèi)型,當(dāng)char類(lèi)型有表示中文字符 時(shí),會(huì)出現(xiàn)亂碼。
這是因?yàn)閿?shù)據(jù)庫(kù)默認(rèn)使用ascII編碼方式。所以要想正確從數(shù)據(jù)庫(kù)中取出中文,需要用 NSString來(lái)接收從數(shù)據(jù)庫(kù)取出的字符串。
如果引入第三方庫(kù)會(huì)變得簡(jiǎn)單很多 比如FMDB。

讀取


1.讀取工程內(nèi)的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數(shù)據(jù)轉(zhuǎn)為NSArray或者NSDictionary
</code>

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容