每個應用程式裡都有一個 Document 資料夾,內容通常存放一些動態的使用者資料,與一般暫存區不同的是 Document 資料夾中的檔案在結束應用程式之後,仍然會保留,因此你可以將一些應用程式的環境設定參數存入其中,以便在下一次執行應用程式時做環境上的設定。下面將以 plist(Property List)檔案為例,實作讀取、寫入、清除等動作。
讀取檔案
在讀取檔案的部份,首先要取得在 Document 中的檔案路徑,之後我們利用該路徑來判斷檔案是否存在,才予以讀取。
//取得plist檔案路徑
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingString:@"/Data.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
//判斷plist檔案存在才讀取
if ([fileManager fileExistsAtPath: filePath]) {
NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
[textView setText:[NSString stringWithFormat:@"%@", data]];
} else{
[textView setText:@"沒有資料,讀取失敗!"];
}
寫入檔案
在寫入檔案的部份,主要分成設定資料與覆寫兩部分,它門主要的差異所要操作的檔案是否已經存在於 Document 中,如果檔案已經存在就直接讀取檔案資料來做修改,否則就建立新的檔案。
//取得plist檔案路徑
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingString:@"/Data.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSMutableDictionary *data;
//判斷plist檔案是否存在於對應位置
if ([fileManager fileExistsAtPath: filePath]) {
//讀取存在的plist檔案,之後等待覆寫
data = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
} else {
//在對應位置中建立plist檔案
data = [[NSMutableDictionary alloc] init];
}
//覆寫or設定參數值
[data setValue:[NSString stringWithFormat:@"%0.f", [hp_Slider value]] forKey:@"HP"];
[data setValue:[NSString stringWithFormat:@"%0.f", [mp_Slider value]] forKey:@"MP"];
[data setValue:[NSString stringWithFormat:@"%0.f", [atk_Slider value]] forKey:@"ATK"];
[data setValue:[NSString stringWithFormat:@"%0.f", [def_Slider value]] forKey:@"DEF"];
//將plist檔案存入Document
if ([data writeToFile:filePath atomically: YES]) {
[textView setText:@"資料寫入成功!"];
} else {
[textView setText:@"資料寫入失敗!"];
}
清除檔案
在清除檔案的部份,同樣先判斷檔案是否存在於 Document 中,才予以刪除。
//取得plist檔案路徑
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingString:@"/Data.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
//判斷plist檔案存在時才刪除
if ([fileManager fileExistsAtPath: filePath]) {
[fileManager removeItemAtPath:filePath error:NULL];
[textView setText:@"資料清除成功!"];
}
其他的資料存放路徑
在應用程式中還存在著其他的檔案存放路徑,像是常用到的專案內的靜態檔案路徑 pathForResource 或是資料暫存區 NSTemporaryDirectory() 等下面就列出一些常用的檔案存放路徑。
//專案中的靜態檔案
NSString *path = [[NSBundle mainBundle] pathForResource:@"檔名" ofType:@"副檔名"];
//應用程式的家目錄
NSString *path = NSHomeDirectory();
//應用程式的暫存區
NSString *path = NSTemporaryDirectory();
最後,如果想要更有系統的存取大筆資料,可以考慮使用內建的輕量資料庫 SQLite3,關於 SQLite3 的基本使用方式可以參考 SQLite3 的取值方式一文。
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
回覆刪除NSString *documentsDirectory = [paths objectAtIndex:0];
請問這一段是什麼意思呢?
新手上路
便當您好:
刪除NSArray *paths 這一行主要是告訴系統要去哪裡找檔案,癟就是我們告訴系統你只能在這個範圍「NSUserDomainMask」裡尋找檔案。
NSString *documentsDirectory 則是把路徑 paths 轉換成字串,因為上述程式碼所得到的 path 是一個陣列,你可以自己將他傾印出來看看,
[paths objectAtIndex:0] ,只是指到這個陣列的第一個位置,就這樣!
這兩段程式碼和在一起就是,去目標位址找出檔案的存放路徑。
//在對應位置中建立plist檔案
回覆刪除data = [[NSMutableDictionary alloc] init];
我試著copy這段code至程式內,發現位置內也並沒有plist檔案產生,
請問我該如何由code中建立檔案
您好:
刪除請問您是如何檢視沒有產生,它是屬於隱藏的資料夾,是無法從專案中看到...
你可以試著取值回來就會知道有沒有成功
if ([fileManager fileExistsAtPath: filePath]) {
回覆刪除//讀取存在的plist檔案,之後等待覆寫
data = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
} else {
//在對應位置中建立plist檔案
data = [[NSMutableDictionary alloc] init];
}
您好!我複製這段程式碼這在其中加上NSlog顯示是否成功.結果一直是失敗的訊息,而且我用finder找尋filePath(我有用NSlog將路徑印出來)先找Library-->application support-->iphone-->6.0....結果其中真的並無檔案產生.....我先問如果要生成檔案的指令是否就是
data = [[NSMutableDictionary alloc] init];
您好
刪除因為你沒有檔案才會失敗,這邊並沒有建立檔案,是假設檔案已經存在了!
data = [[NSMutableDictionary alloc] init]; 只是對NSMutableDictionary初始化
您好!
回覆刪除那請教一下.可以從程式中create檔案嗎?
如果可以那我應該如何去做?
謝謝您的細心解答!
您好
回覆刪除我在stackoverflow中幫您找了這一篇,除了動態產生plist檔案之外,他還可以賦予key值,並存放於Documents中,可以參考看看。
http://stackoverflow.com/questions/6697247/how-to-create-plist-files-programmatically-in-iphone
您好!
回覆刪除謝謝您抽空幫我找資訊...
不過看過之後
NSFileManager *fileManager = [NSFileManager defaultManager];
NSMutableDictionary *data;
if ([fileManager fileExistsAtPath: path])
{
data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
}
else
{
// If the file doesn’t exist, create an empty dictionary
data = [[NSMutableDictionary alloc] init];
}
這一段跟您所寫的不是一樣嗎?
還是小弟我找錯了嗎?
再麻煩您了!謝謝您
您好
回覆刪除看過您給的網站發現
if ([fileManager fileExistsAtPath: path])
{
data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
}
else
{
// If the file doesn’t exist, create an empty dictionary
data = [[NSMutableDictionary alloc] init];
}
這一段不是跟您所寫的一樣嗎?
順便請教您.您寫這篇文章時,Plist檔案您是如何產生的....?
謝謝您
您好:
刪除我是使用動態方式產生的plist的,在建立檔案的部分 [data writeToFile:filePath atomically: YES] 才是將檔案寫入目標位置的程式碼,您所提到的
data = [[NSMutableDictionary alloc] init] 這邊只是將NSData初始化,並沒有任何寫入的動作。
如果你有任何問題,歡迎你來信至 furnacedigital@gmail.com ,我們很樂意與您分享這個範例的程式碼。
這篇是找到Document裡的plist檔案然後修改,請問:如果是別的檔,如 js (javascript),要如何讀取其內容並修改? 謝謝
回覆刪除您好:
刪除使用 NSFileManager 可以針對檔案做移動、複製、刪除、讀取和改寫入動作,但是這些皆不包含改變檔案的內容,如果想要製作文字檔案像是 txt html 或是您提到的 js 等等,可以使用 NSMutableString 來整合這些字串集,或是使用 NSString 的初始畫函式 initWithContentsOfFile: encoding: error: 來取得檔案內的字串。 - See more at: http://furnacedigital.blogspot.tw/2012/03/document.html?showComment=1376458901133#c88967856429912081
請問 plist是不是不能存入中文呢?小弟想用plist當成所有class的全域變數,但發現無法存入中文,需要轉碼,請問有可以讓變數在全部class通用的方法嗎?感謝
回覆刪除您好:
刪除不能用中文、就算可以也盡量避免,才不會有編碼上的錯誤。
另外讓變數在全部class通用的方法,你可以參考這一篇:
http://furnacedigital.blogspot.tw/2012/07/class.html
sigleton class 可以 解決你的需求
您好,看到上一個問題,想請問使用plist當全域變數不好嗎?如果需求是在程式重啟後變數仍存在,那是不是使用plist是最好的方法?謝謝您,您的blog真的對初學者幫助非常的大!
回覆刪除豆腐 您好:
刪除plist當全域變數這個問題,當然ok的,不過有可能導致以下這些問題產生。
- 必須在每個class中都包含相同的程式碼「讀取」與「存入」,這些指令不像我們在使用一般變數一樣簡單。
- 另一個就是我們在玩game時會遇到的存檔機制,存檔,遇到過不了的地方(bug),關掉遊戲再讀取檔案,如果不把plist和全域變數拆開設計,這部份會很難實行。
最後,如果你的程式很小可以忽略這些,當然plist是可以當做全域變數使用,但是plist還有一個無法取代全域變數的地方,就是當app關閉時,全域變數便會「釋放」,plist卻會存在你的檔案資料夾中....直到永遠!
豆腐 您好:
刪除不知道為什麼我看不到你的留言,只有看到 blogger 轉發的 mail。
如果你的目的是「但我希望變數在程式重開啟後仍存在」,這個就是存檔機制啦,既然是存「檔」,表示要有地方放這些資料,這時候你說的plist就是一個可行的例子,不過在執行階段(run time)通常還是會用全域變數以較方便,只要在結束時或是特定時間轉存回plist上就可以了。
所以我才會以game存檔的例子來舉例,你的思路也沒問題!!
但我希望變數在程式重開啟後仍存在,使用全域變數會釋放,這樣不就無法實現存檔機制了?以您提到game存檔的例子,所以我應該是要在程式運行時使用全域變數,而當要進行存檔動作時再將其寫入plist、sqlite、xml等資料中,這樣的思路對嗎?新手上路很感謝您的細心指教。
回覆刪除