本文參看了 http://www.uml.org.cn/mobiledev/201209211.asp#1 這篇文章中的介紹,尊重原著。
1、IOS沙箱機制
IOS應用程式只能在本應用程式中建立的檔案系統中讀取檔案,不可以去其它地方訪問,此地區被成為沙箱,所有的非代碼檔案都要儲存在此,例像,表徵圖,聲音,映像,屬性列表,文字檔等。
1.1、每個應用程式都有自己的儲存空間
1.2、應用程式不能翻過自己的圍牆去訪問別的儲存空間的內容
1.3、應用程式請求的資料都要通過許可權檢測,假如不合格話,不會被允許存取。
通過這張圖只能從表層上理解sandbox是一種安全體系,應用程式的所有操作都要通過這個體系來執行,其中核心內容是:sandbox對應用程式執行各種操作的許可權限制。
2、開啟模擬器沙箱目錄
下面看看模擬器的沙箱檔案夾在mac電腦上的什麼位置。
檔案都在個人使用者名稱檔案夾下的一個隱藏檔案夾裡,中文叫資產庫,英文名是Library。
下面介紹一種簡單方法前往該檔案夾:在Finder上點->前往->前往檔案夾
進入模擬器後,裡面就包含了各個應用程式的沙箱。
進入一個應用程式,如,就是一個沙箱了。
下面介紹一下沙箱的目錄結構:
預設情況下,每個沙箱含有3個檔案夾:Documents, Library 和 tmp和一個應用程式檔案(也是一個檔案)。因為應用的沙箱機制,應用只能在幾個目錄下讀寫檔案
Documents:蘋果建議將程式中建立的或在程式中瀏覽到的檔案資料儲存在該目錄下,iTunes備份和恢複的時候會包括此目錄
Library:儲存程式的預設設定或其它狀態資訊;
Library/Caches:存放快取檔案,iTunes不會備份此目錄,此目錄下檔案不會在應用退出刪除
tmp:提供一個即時建立臨時檔案的地方。
iTunes在與iPhone同步時,備份所有的Documents和Library檔案。
iPhone在重啟時,會丟棄所有的tmp檔案。
注意:這裡很容易和bundle混淆在一起,下面根據自己的一點理解說明二者的區別:
bundle :產生 iOS 應用程式時,Xcode 將它捆綁成一個包。捆綁包 (bundle) 是檔案系統中的一個目錄,它將相關資源成組在一個地方。一個 iOS 應用程式捆綁包中,含有其可執行檔和支援資源檔(如應用程式圖示、影像檔和已本地化的內容)。
A bundle(包裹、捆、束) is a directory with a standardizedhierarchical structure that holds executable code and the resources used by that code.
所以可以將整個應用程式其實就可以看做一個bundle。
沙箱的概念和bundle沒直接關係,沙箱只是說明程式資源與外界隔離
下面通過一個簡單的例子說明一下bundle和sandbox。
//建立的plist檔案是在應用程式中的,可以通過bundle存取到該檔案 NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"MyPlist" ofType:@"plist"]; NSMutableArray *array = [NSMutableArray arrayWithContentsOfFile:plistPath]; //向數組中新添加一個項目 [array addObject:@"3"]; //重新寫回plist檔案中 BOOL value = [array writeToFile:plistPath atomically:YES]; if (value) { NSMutableArray *newArray = [NSMutableArray arrayWithContentsOfFile:plistPath]; NSLog(@"new array = %@",newArray); } /* 輸出: new array = ( 0, 1, 2, 3 ) */ //擷取沙箱中document的目錄(絕對路徑) NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *newPath = [documentsDirectory stringByAppendingPathComponent:@"data.plist"]; //將數組寫入到沙箱的document中的data.plist檔案中 [array writeToFile:newPath atomically:YES]; NSMutableArray *arr = [[NSMutableArray alloc] initWithContentsOfFile:newPath]; NSLog(@"array in data.plist = %@",arr); /* 輸出: array in data.plist = ( 0, 1, 2, 3 ) */
說明:我們首先在項目中建立一個plist檔案(root項的類型為數組),添加了3個元素。因為建立的plist檔案是在應用程式中的,我們可以通過bundle擷取到這個plist檔案,讀取出這個數組,添加一個資料元素後,重新寫回plist檔案中。接著我們擷取沙箱document的目錄,然後將這個檔案寫入到沙箱中的data.plist檔案中(如果不存在,會自動建立一個的),然後再從data.plist讀取出這個數組。
關於建立的MyPlist.plist檔案,我們寫迴文件的數組中添加了一項新的元素,但是我們在xcode中查看這個MyPlist.plist檔案時,發現並沒有顯示出新增的數組元素,但是我們到沙箱中查看就可以看到了,這個估計是xoode本身的問題。
關於document中data.plist檔案查看我們也可以到沙箱中進行查看。如:
3、擷取沙箱目錄:
//1、擷取程式的Home目錄 NSString *homeDirectory = NSHomeDirectory(); NSLog(@"path:%@", homeDirectory); //path:/Users/ios/Library/Application Support/iPhone Simulator/6.1/Applications/BF38C9E3-1A4A-4929-B5F2-3E46E41CC671 //2、擷取document目錄 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *path = [paths objectAtIndex:0]; NSLog(@"path:%@", path); //path:/Users/ios/Library/Application Support/iPhone Simulator/6.1/Applications/BF38C9E3-1A4A-4929-B5F2-3E46E41CC671/Documents //3、擷取Cache目錄 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *path = [paths objectAtIndex:0]; NSLog(@"path:%@", path); //path:/Users/ios/Library/Application Support/iPhone Simulator/6.1/Applications/BF38C9E3-1A4A-4929-B5F2-3E46E41CC671/Library/Caches //4、擷取Library目錄 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); NSString *path = [paths objectAtIndex:0]; NSLog(@"path:%@", path); //path:/Users/ios/Library/Application Support/iPhone Simulator/6.1/Applications/BF38C9E3-1A4A-4929-B5F2-3E46E41CC671/Library //5、擷取tmp目錄 NSString *tmpDir = NSTemporaryDirectory(); NSLog(@"path:%@", tmpDir); //path:/Users/ios/Library/Application Support/iPhone Simulator/6.1/Applications/BF38C9E3-1A4A-4929-B5F2-3E46E41CC671/tmp/
4、檔案操作之NSFileManager
4.1 、在document中建立一個檔案目錄
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSLog(@"documentsDirectory%@",documentsDirectory); NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *testDirectory = [documentsDirectory stringByAppendingPathComponent:@"test"]; // 建立目錄 [fileManager createDirectoryAtPath:testDirectory withIntermediateDirectories:YES attributes:nil error:nil];
4.2 、 在test目錄下建立檔案
建立檔案怎麼辦呢?接著上面的代碼 testPath 要用stringByAppendingPathComponent拼接上你要產生的檔案名稱,比如test11.txt。這樣才能在test目錄下寫入檔案。
testDirectory是上面代碼產生的路徑哦,不要忘了。我往test檔案夾裡寫入三個檔案,test11.txt ,test22.txt,text.33.txt。內容都是寫入內容,write String。
實現代碼如下:
NSString *testPath1 = [testDirectory stringByAppendingPathComponent:@"test1.txt"]; NSString *testPath2 = [testDirectory stringByAppendingPathComponent:@"test2.txt"]; NSString *testPath3 = [testDirectory stringByAppendingPathComponent:@"test3.txt"]; NSString *string = @"寫入內容,write String"; [fileManager createFileAtPath:testPath1 contents:[string dataUsingEncoding:NSUTF8StringEncoding] attributes:nil]; [fileManager createFileAtPath:testPath2 contents:[string dataUsingEncoding:NSUTF8StringEncoding] attributes:nil]; [fileManager createFileAtPath:testPath3 contents:[string dataUsingEncoding:NSUTF8StringEncoding] attributes:nil];
4.3擷取目錄列裡所有檔案名稱
兩種方法擷取:subpathsOfDirectoryAtPath
和 subpathsAtPath
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSLog(@"documentsDirectory%@",documentsDirectory); NSFileManager *fileManage = [NSFileManager defaultManager]; NSString *myDirectory = [documentsDirectory stringByAppendingPathComponent:@"test"]; //方法一 NSArray *file = [fileManage subpathsOfDirectoryAtPath: myDirectory error:nil]; NSLog(@"%@",file); //方法二 NSArray *files = [fileManage subpathsAtPath: myDirectory ]; NSLog(@"%@",files);
擷取剛才test目錄下的所以檔案名稱:
兩種方法都是輸出
( "test1.txt", "test2.txt", "test3.txt")
4.4 、fileManager使用操作目前的目錄
//建立檔案管理工具 NSFileManager *fileManager = [NSFileManager defaultManager]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; //更改到待操作的目錄下 [fileManager changeCurrentDirectoryPath:[documentsDirectory stringByExpandingTildeInPath]]; //建立檔案fileName檔案名稱,contents檔案的內容,如果開始沒有內容可以設定為nil,attributes檔案的屬性,初始為nil NSString * fileName = @"testFileNSFileManager.txt"; NSArray *array = [[NSArray alloc] initWithObjects:@"hello world",@"hello world1", @"hello world2",nil]; //下面是將數群組類型轉換為NSData類型 NSMutableData *data = [[NSMutableData alloc] init]; for (int i = 0; i < [array count]; ++i ){ NSString *str = [array objectAtIndex:i]; NSData *temp = [str dataUsingEncoding:NSUTF8StringEncoding]; [data appendData:temp]; } //注意contents參數的類型是NSData類型 [fileManager createFileAtPath:fileName contents:data attributes:nil];
4.5 刪除檔案
接著上面的代碼就可以將剛建立的 testFileNSFileManager.txt檔案刪除!
[fileManager removeItemAtPath:fileName error:nil];
4.6 混合資料的讀寫 請參看原文最後面的內容。
大概就是這麼多了吧!