iOS - 沙盒文件操作指南
前言
最近在學(xué)習(xí)數(shù)據(jù)持久化相關(guān)的內(nèi)容,文件作為 iOS 客戶端開發(fā)中一種常見的數(shù)據(jù)保存方式,自然也是應(yīng)該學(xué)習(xí)的內(nèi)容,本文就來簡單介紹文件相關(guān)的一些知識。
文章目錄
- 前言
- 1. 文件基礎(chǔ)
- 沙盒路徑獲取
- NSString 路徑操作
- NSData 類型轉(zhuǎn)換
- 2. NSFileManager 文件操作
- 2.1 創(chuàng)建文件和目錄
- 2.2 文件剪切和復(fù)制
- 2.3 文件刪除
- 3. NSFileHandle 文件讀寫
- 3.1 常用方法
- 參考資料
1. 文件基礎(chǔ)
在 iOS 系統(tǒng)中,所有非系統(tǒng)應(yīng)用都經(jīng)過了沙盒化,每個應(yīng)用都擁有自己的沙盒(Sandbox)用于存儲本應(yīng)用的文件數(shù)據(jù),不同應(yīng)用沙盒之間是相互獨立的,而且本應(yīng)用不能訪問其他應(yīng)用的沙盒。
沙盒機制保證了 iOS 應(yīng)用的安全性,能有效防止 App 收集和篡改其他 App 存儲的信息。如果第三方 App 需要訪問除自身以外的其他信息,只能通過 iOS 系統(tǒng)明確提供的服務(wù)來實現(xiàn)。
應(yīng)用沙盒的結(jié)構(gòu)如下圖所示:
下面簡單介紹一下沙盒各個路徑的內(nèi)容:
- /Document 目錄:用于存放程序中的文件數(shù)據(jù),應(yīng)用程序在運行時生成一些需要長久保存的數(shù)據(jù),如游戲進(jìn)程存檔,為編輯完的文檔等。iTunes 、iCloud 對應(yīng)用信息備份時,會備份這個目錄下的數(shù)據(jù),因此會在此目錄保存相對重要的數(shù)據(jù)。
- /Library 包含下面兩個子目錄
- /Library/Caches 目錄 :恰如其名,該目錄用于存放緩存文件,從網(wǎng)絡(luò)上下載的文件或數(shù)據(jù)(如:音樂緩存、圖片緩存等)都會保存在該目錄下。該目錄下的文件不會在應(yīng)用退出時手動刪除,需要程序員手動清除該目錄下的數(shù)據(jù)。iTunes 、iCloud 不會對該目錄下的數(shù)據(jù)進(jìn)行備份。
- /Library/Preferences 目錄:存放的是基于 NSUserDefaults 的設(shè)置數(shù)據(jù),文件格式為 .plist。設(shè)置應(yīng)用的一些功能會在該目錄中查找相應(yīng)設(shè)置的信息,iTunes、iCloud備份時會備份此目錄下的數(shù)據(jù)。該目錄由系統(tǒng)自動管理,通常用來儲存一些基本的應(yīng)用配置信息。
- /Temp 目錄:存放應(yīng)用運行時產(chǎn)生的一些臨時數(shù)據(jù)和文件,當(dāng)應(yīng)用程序退出、系統(tǒng)磁盤空間不足、手機重啟時,都會自動清除該目錄的數(shù)據(jù)。無需程序員手動清除該目錄中的數(shù)據(jù),iTunes、iCloud備份時不會備份此目錄。
沙盒路徑獲取
我們可以通過下面的方法,獲取到上面提及到的沙盒目錄。
// 獲取沙盒根目錄 NSString *homeDir = NSHomeDirectory();// 獲取 /Document 目錄 NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];// 獲取 /Library 目錄 NSString *libDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory , NSUserDomainMask , YES) lastObject];// 獲取 /Library/Caches 目錄 NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];// 獲取 /Temp 目錄 NSString *tmpDir = NSTemporaryDirectory();NSString 路徑操作
要想對文件進(jìn)行操作,必然會涉及到文件路徑的處理。在 NSString 中,也給我們提供了路徑操作相關(guān)的 API。
/// 路徑分解,例如 /Users/Apple/file.txt 會得到 "/", "Users", "Apple", "file.txt" - (NSArray *)pathComponents;// 獲取路徑的最后部分,例如 /Users/Apple/file.txt 會得到 "file.txt" - (NSString *)lastPathComponent;// 在路徑末尾添加路徑,會自動處理 "/" - (NSString *)stringByAppendingPathConmponent:(NSString *)str;// 刪除路徑的最后部分,例如 /Users/Apple/file.txt 會得到 /Users/Apple/ - (NSString *)stringByDeletingLastPathCpmponent;// 為路徑添加拓展名,傳參的時候不用加 "." - (NSString *)stringByAppendingPathExtension:(NSString *)str;// 刪除路徑末尾的拓展名 - (NSString *)stringByDeletingPathExtension;NSData 類型轉(zhuǎn)換
我們讀取文件時,通常獲取到的都是 NSData 類型的對象,下面是 NSData 到其他常用類型的相互轉(zhuǎn)換方法。
// NSString 和 NSData 互轉(zhuǎn) NSString *str = @"Veggie"; NSData *strToData = [str dataUsingEncoding:NSUTF8StringEncoding]; NSString *dataToStr = [[NSString alloc] initWithData:strToData encoding:NSUTF8StringEncoding];// int 和 NSData 互轉(zhuǎn) int i = 1024; NSData *intToData = [NSData dataWithBytes:&i length:sizeof(i)]; int dataToInt; [intToData getBytes:&dataToInt length:sizeof(dataToInt)];// UIImage 和 NSData 互轉(zhuǎn) UIImage *image = [UIImage imageNamed:@"test"]; NSData *imageToData = UIImagePNGRepresentation(image); UIImage *dataToImage = [UIImage imageWithData:imageToData];// NSArray 和 NSData 互轉(zhuǎn) NSArray *arr = @[@"1", @"2", @"3"]; NSData *arrToData = [NSJSONSerialization dataWithJSONObject:arr options:NSJSONWritingPrettyPrinted error:nil]; NSArray *dataToArr = [NSJSONSerialization JSONObjectWithData:arrToData options:NSJSONReadingMutableContainers error:nil];// NSDictionary 和 NSData 互轉(zhuǎn) NSDictionary *dic = @{@"user_name" : @"veggie",@"user_age" : @"18" }; NSData *dicToData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil]; NSArray *dataToDic = [NSJSONSerialization JSONObjectWithData:dicToData options:NSJSONReadingMutableContainers error:nil];2. NSFileManager 文件操作
我們想對沙盒中的目錄和文件進(jìn)行操作時,可以用上系統(tǒng)為我們提供的 NSFileManager 文件管理類。下面就通過封裝方法的形式,簡單介紹 NSFileManager 的使用。
2.1 創(chuàng)建文件和目錄
創(chuàng)建目錄
- (BOOL)createDir:(NSString *)path {NSAssert(path > 0, @"%s: The length of path should be greater than 0.", __FUNCTION__);NSFileManager *fileManager = [NSFileManager defaultManager];BOOL isSuccess = YES;// 判斷目錄是否已經(jīng)存在if (![fileManager fileExistsAtPath:path]) {// 創(chuàng)建文件目錄NSError *error = nil;isSuccess = [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&error];if (error) {NSLog(@"Create directory failed: %@",[error localizedDescription]);}}return isSuccess; }創(chuàng)建文件,在創(chuàng)建之前需要確定文件的存儲路徑是存在的,如果不存在,則現(xiàn)在執(zhí)行目錄創(chuàng)建操作。
- (BOOL)createFile:(NSString *)filePath {NSAssert(filePath > 0, @"%s: The length of filePath should be greater than 0.", __FUNCTION__);NSFileManager *fileManager = [NSFileManager defaultManager];// 提取出文件存放的目錄NSString *dir = [filePath stringByDeletingLastPathComponent];// 判斷目錄是否已經(jīng)存在if (![fileManager fileExistsAtPath:dir]) {// 如果還沒有存在,則需要新建NSError *error = nil;[fileManager createDirectoryAtPath:dir withIntermediateDirectories:YES attributes:nil error:&error];if (error) {NSLog(@"Create directory failed: %@",[error localizedDescription]);return NO;}}// 創(chuàng)建文件return [fileManager createFileAtPath:filePath contents:nil attributes:nil]; }2.2 文件剪切和復(fù)制
這里以一個簡單的任務(wù)來舉例,我們需要將 /Documents/from 目錄下的所有文件(文件名格式有規(guī)律)移動到 /Documents/to 目錄下,其目錄內(nèi)容如下圖所示。
我們使用 NSFileManager 來實現(xiàn),代碼如下:
復(fù)制操作和上面的代碼非常詳細(xì),用到的是下面這個 API,需要特別注意的是,參數(shù)中 srcPath 和 dstPath 路徑都要拼上文件名。
- (BOOL)copyItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error;2.3 文件刪除
- (BOOL)deleteFile:(NSString *)filePath {NSError *error = nil;NSFileManager *fileManager = [NSFileManager defaultManager];BOOL isSuccess = [fileManager removeItemAtPath:filePath error:&error];if (error) {NSLog(@"removeFile Field:%@",[error localizedDescription]);}return isSuccess; }3. NSFileHandle 文件讀寫
NSFileHandle 主要用于對文件進(jìn)行 I/O 操作,它的使用通常包括以下幾個步驟:
- 打開文件,獲取文件對應(yīng)的 NSFileHandle 對象
- 對該文件執(zhí)行 I/O 操作(讀取、寫入、插入)
- 關(guān)閉文件
3.1 常用方法
// 打開一個文件,準(zhǔn)備讀取 + (nullable instancetype)fileHandleForReadingAtPath:(NSString *)path; // 打開一個文件,準(zhǔn)備寫入(會發(fā)生覆蓋) + (nullable instancetype)fileHandleForWritingAtPath:(NSString *)path; // 打開一個文件,準(zhǔn)備插入內(nèi)容 + (nullable instancetype)fileHandleForUpdatingAtPath:(NSString *)path;// 返回可用的數(shù)據(jù) - (NSData *)availableData; // 從當(dāng)前的節(jié)點讀取到文件的末尾 - (NSData *)readDataToEndOfFile; // 從當(dāng)前節(jié)點開始讀取指定的長度數(shù)據(jù) - (NSData *)readDataOfLength:(NSUInteger)length; // 寫入數(shù)據(jù) - (void)writeData:(NSData *)data; // 獲取當(dāng)前文件的偏移量 - (unsigned long long)offsetInFile; // 跳到指定文件的偏移量 - (void)seekToFileOffset:(unsigned long long)offset; // 跳到文件末尾 - (unsigned long long)seekToEndOfFile; // 將文件的長度設(shè)為offset字節(jié) - (void)truncateFileAtOffset:(unsigned long long)offset; // 關(guān)閉文件 - (void)closeFile;參考資料
- File System Programming Guide | Apple Developer Documentation
- NSFileManager | Apple Developer Documentation
- NSString | Apple Developer Documentation
- NSData | Apple Developer Documentation
好像又寫了一篇沒什么用的文章,希望后面在開發(fā)中用上了相關(guān)技術(shù),可以再次回到這里更新自己的想法。
總結(jié)
以上是生活随笔為你收集整理的iOS - 沙盒文件操作指南的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS - 数据的归档和反归档
- 下一篇: iOS - 使用 SQLite 数据库实