iOS 沙盒機制 持久存儲 讀寫文件 NSFileManager


  • 沙盒機制

每一個iOS應用程序都會為自己創建一個文件系統目錄(文件夾),這個獨立、封閉、安全的空間叫做沙盒。沙盒就是一種安全體系,它規定了應用程序只能在為該應用程序創建的文件夾(沙盒)內訪問文件,不可以訪問其他沙盒內的內容(iOS8已經部分開放訪問)。所有的非代碼文件都保存在這個地方,比如圖片、聲音、屬性列表(plist)、sqlite數據庫和文本文件等。

總結iOS的沙盒機制的特點:

1、每個應用程序的活動范圍都限定在自己的沙盒里

2、不能隨意跨越自己的沙盒去訪問別的應用程序沙盒中的內容(iOS8已經部分開放訪問)

3、應用程序向外請求或接收數據都需要經過權限認證

注:1、每一個應用程序都會擁有一個應用程序沙盒。

      2、應用程序沙盒就是一個文件系統目錄。

沙盒根目錄結構:Documents、Library、temp。

Documents:保存應用運行時生成的需要持久化的數據,iTunes備份和恢復的時候會包括此目錄,所以蘋果建議將程序中建立的或在程序中瀏覽到的文件數據保存在該目錄下。

Library:存儲程序的默認設置和其他狀態信息,iTunes會自動備份該目錄。包含兩個子目錄:Caches 和 Preferences

     Caches:存放緩存文件,iTunes不會備份此目錄,此目錄下文件不會在應用退出后刪除 。一般存放體積比較大,不是特別重要的資源。

     Preferences:保存APP的所有偏好設置,iOS的Settings(設置)應用會在該目錄中查找應用的設置信息,iTunes會自動備份該目錄。注意:通過NSUserDefaults類來讀取和設置。

tmp: 保存應用運行時所需的臨時數據,這個可以放一些當APP退出后不再需要的文件。應用沒有運行時,系統也有可能會清除該目錄下的文件,iTunes不會同步該目錄。iPhone重啟時,該目錄下的文件會被刪除。

  • 打開沙盒方法

方法一:前往文件夾打開/Users/xuxiaoliu/Library/Application Support/iPhone Simulator/ 

方法二:通過Finder一步步查找

模擬器上的APP的沙盒是在用戶目錄下的資源庫里面,但是資源庫是隱藏文件夾。所以查看沙盒之前,現將隱藏文件夾顯示出來。

顯示隱藏文件的命令:defaults write com.apple.finder AppleShowAllFiles -bool true

隱藏隱藏文件的命令:defaults write com.apple.finder AppleShowAllFiles -bool false

另:真機上的APP沙盒路徑是 /var/mobile/Containers/Data/Application/C778116A-B066-4C5C-8BBC-28E91405DA44/Documents

// 獲取Document目錄
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
 
// 獲取Library目錄
NSString *LibraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
 
// 獲取Caches目錄
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
 
// 獲取Preferences目錄 通常情況下,Preferences有系統維護,所以我們很少去操作它。
NSString *preferPath = [LibraryPath stringByAppendingPathComponent:@"Preferences"];

// 獲取tmp目錄
NSString *tmpPath = NSTemporaryDirectory();

 

 

一:簡單對象的讀寫(I/O)操作

簡單對象:iOS中提供四種類型可以直接進行文件存取:NSString(字符串)、NSArray(數組)、NSDictionary(字典)、NSData(數據)(以上類型包括子類)

注意:數組(可變與不可變)和字典(可變與不可變)中元素對象的類型,也必須是上述四種,否則不能直接寫入文件

 

字符串對象寫入文件

//構造字符串文件的存儲路徑

NSString *strPath = [documentPath stringByAppendingPathComponent:@"text.txt"];

//構造字符串對象

NSString *foo_str = @"this is a test";

//通過將writeToFile:atomically:encoding:error:方法發送給字符串對象完成字符串存儲到文件內的功能

[foo_str writeToFile:strPath atomically:YES encoding:NSUTF8StringEncoding error:nil];

從文件中讀取字符串對象

NSString *str = [NSString stringWithContentsOfFile:strPath encoding:NSUTF8StringEncoding error:nil];

 

Plist文件

全名是:Property List,屬性列表文件,它是一種用來存儲串行化后的對象的文件。屬性列表文件的擴展名為.plist,因此通常被成為plist文件。文件是xml格式的

Plist文件通常用於存儲用戶設置,也可以用於存儲捆綁的信息。

 

NSData寫入/讀取

NSData對象寫入文件

UIImage *image = [UIImage imageNamed:@"圖片名"];

NSData *foo_data = UIImagePNGRepresentation(image);

//構造二進制文件的存儲路徑

NSString *dataPath = [documentPath stringByAppendingPathComponent@"data"];

//通過將writeToFile:atomically:方法發送給二進制對象完成二進制存儲到文件內的功能

[foo_data writeToFile:dataPath atomically:YES];

注:二進制對象可能存儲的是圖像、字符串等等。

從文件中讀取NSData數據

NSData *data = [NSData dataWithContentsOfFile:dataPath];

UIImage *image = [UIImage imageWithData:data];

 
 

二、文件管理器與文件對接器

文件管理器(NSFileManager):此類主要是對文件進行的操作(創建/刪除/改名等)以及文件信息的獲取。

文件連接器(NSFileHandle):此類主要是對文件內容進行讀取和寫入操作。

 
文件管理器:
1、創建文件管理器對象 NSFileManager = [NSFileManager defaultManager];
2、創建一個文件並寫入數據 - (BOOL)createFileAtPath:(NSString *)path contents:(NSData *)data attributes:(NSDictionary *)dic;
3、從一個文件中讀取數據 - (NSData *)contentsAtPath:(NSString *)path;
4、srcPath路徑上的文件移動到desPath路徑上。(注意這里的路徑是文件路徑而不是目錄) - (BOOL)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)desPath error:(NSError *)error;
 
文件連接器:
1、打開一個文件准備讀取 + (id)fileHandleForReadingAtPath:(NSString *)path;
2、打開一個文件准備寫入 + (id)fileHandleForWritingAtPath:(NSString *)path;
3、打開一個文件准備更新 + (id)fileHandleForUpdatingAtPath:(NSString *)path;
4、從設備或通道返回可用的數據 - (NSData *)availableData;
5、從當前的節點讀取到文件的末尾 - (NSData *)readDataToEndOfFile;
6、從當前的節點開始讀取指定的長度數據 - (NSData *)readDataOfLength:(NSUInteger)length;
7、寫入數據 - (void)writeData:(NSData *)data;
8、獲取當前文件的偏移量 - (unsigned long long)offsetInFile;
9、跳到指定文件的偏移量 - (void)seekToFileOffset:(unsigned long long)offset;
10、跳到文件末尾 - (unsigned long long)seekToEndOfFile;
11、將文件的長度設為offset字節 - (void)truncateFileAtOffset:(unsigned long long)offset;
12、關閉文件 - (void)closeFile;
 
// 獲取Documents路徑
- (NSString *)getDocumentsPath {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *path = [paths objectAtIndex:0];
    NSLog(@"path:%@", path);
    return path;
}

// 創建文件夾
- void)createDirectory {
    NSString *documentsPath =[self getDocumentsPath];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *iOSDirectory = [documentsPath stringByAppendingPathComponent:@"iOS"];
    BOOL isSuccess = [fileManager createDirectoryAtPath:iOSDirectory withIntermediateDirectories:YES attributes:nil error:nil];
    if (isSuccess) {
        NSLog(@"success");
    } else {
        NSLog(@"fail");
    }
}

// 創建文件
- (void)createFile {
    NSString *documentsPath =[self getDocumentsPath];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *iOSPath = [documentsPath stringByAppendingPathComponent:@"iOS.txt"];
    BOOL isSuccess = [fileManager createFileAtPath:iOSPath contents:nil attributes:nil];
    if (isSuccess) {
        NSLog(@"success");
    } else {
        NSLog(@"fail");
    }
}

// 寫入文件
- (void)writeFile {
    NSString *documentsPath =[self getDocumentsPath];
    NSString *iOSPath = [documentsPath stringByAppendingPathComponent:@"iOS.txt"];
    NSString *content = @"我要寫數據啦";
    BOOL isSuccess = [content writeToFile:iOSPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
    if (isSuccess) {
        NSLog(@"write success");
    } else {
        NSLog(@"write fail");
    }
}

// 讀取文件
- (void)readFileContent {
    NSString *documentsPath =[self getDocumentsPath];
    NSString *iOSPath = [documentsPath stringByAppendingPathComponent:@"iOS.txt"];
    NSString *content = [NSString stringWithContentsOfFile:iOSPath encoding:NSUTF8StringEncoding error:nil];
    NSLog(@"read success: %@",content);
}

// 判斷文件是否存在
- (BOOL)isSxistAtPath:(NSString *)filePath {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    BOOL isExist = [fileManager fileExistsAtPath:filePath];
    return isExist;
}

// 計算文件大小
- (unsigned long long)fileSizeAtPath:(NSString *)filePath {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    BOOL isExist = [fileManager fileExistsAtPath:filePath];
    if (isExist) {
        unsigned long long fileSize = [[fileManager attributesOfItemAtPath:filePath error:nil] fileSize];
        return fileSize;
    } else {
        NSLog(@"file is not exist");
        return 0;
    }
}

// 計算整個文件夾中所有文件大小
- (unsigned long long)folderSizeAtPath:(NSString*)folderPath {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    BOOL isExist = [fileManager fileExistsAtPath:folderPath];
    if (isExist) {
        NSEnumerator *childFileEnumerator = [[fileManager subpathsAtPath:folderPath] objectEnumerator];
        unsigned long long folderSize = 0;
        NSString *fileName = @"";
        while ((fileName = [childFileEnumerator nextObject]) != nil){
            NSString* fileAbsolutePath = [folderPath stringByAppendingPathComponent:fileName];
            folderSize += [self fileSizeAtPath:fileAbsolutePath];
        }
        return folderSize / (1024.0 * 1024.0);
    } else {
        NSLog(@"file is not exist");
        return 0;
    }
}

// 刪除文件
- (void)deleteFile {
    NSString *documentsPath =[self getDocumentsPath];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *iOSPath = [documentsPath stringByAppendingPathComponent:@"iOS.txt"];
    BOOL isSuccess = [fileManager removeItemAtPath:iOSPath error:nil];
    if (isSuccess) {
        NSLog(@"delete success");
    }else{
        NSLog(@"delete fail");
    }
}

// 移動文件
- (void)moveFileName {
    NSString *documentsPath =[self getDocumentsPath];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *filePath = [documentsPath stringByAppendingPathComponent:@"iOS.txt"];
    NSString *moveToPath = [documentsPath stringByAppendingPathComponent:@"iOS.txt"];
    BOOL isSuccess = [fileManager moveItemAtPath:filePath toPath:moveToPath error:nil];
    if (isSuccess) {
        NSLog(@"rename success");
    }else{
        NSLog(@"rename fail");
    }
}

// 重命名
- (void)renameFileName {
    //通過移動該文件對文件重命名
    NSString *documentsPath =[self getDocumentsPath];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *filePath = [documentsPath stringByAppendingPathComponent:@"iOS.txt"];
    NSString *moveToPath = [documentsPath stringByAppendingPathComponent:@"rename.txt"];
    BOOL isSuccess = [fileManager moveItemAtPath:filePath toPath:moveToPath error:nil];
    if (isSuccess) {
        NSLog(@"rename success");
    }else{
        NSLog(@"rename fail");
    }
}

 

 
 
三、復雜對象的讀寫(I/O)操作
 

什么是復雜對象?

在Foundation框架內不存在的數據類,如:自定義Person類無法在程序內通過writeToFile:這個方法寫入到文件內

 

歸檔與反歸檔

如何將復雜對象寫入文件?

復雜對象無法通過writeToFile:方法進行數據持久化,只能通過將復雜對象轉換為NSData(這個步驟就是歸檔),然后在通過writeToFile:寫入文件

 

如何從文件中讀取復雜對象?

從文件中讀取NSData數據,將NSData轉換為復雜對象(這個步驟就是反歸檔)

記住:1、復雜對象寫入文件的過程(復雜對象->歸檔->NSData->writeToFile)

  2、從文件中讀取出復雜對象過程(讀取文件->NSData->反歸檔->復雜對象)

 

如何進行歸檔與反歸檔

1、首先,復雜對象所屬的類要遵守協議

2、其次,實現協議中的兩個方法:①、- (void)encodeWithCoder:(NSCoder *)aCoder;//序列化 ②、- (id)initWithCoder:(NSCoder *)aDecoder;//反序列化

 


免責聲明!

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



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