iOS 沙盒(sandbox)機制和文件操作


本文參看了 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的path
    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的path,然后將這個文件寫入到沙箱中的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 混合數據的讀寫  請參看原文最后面的內容。


大概就是這么多了吧!


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM