一、沙盒機(jī)制#
沙盒的概念:沙盒是每一個iOS應(yīng)用程序都會自動創(chuàng)建的一個文件系統(tǒng)目錄(文件夾),而且沙盒還具有獨(dú)立、封閉、安全的特點(diǎn)。
沙盒機(jī)制
- iOS中的沙盒不僅僅是一個文件目錄,TA其實(shí)更是一種安全體系
- TA規(guī)定了應(yīng)用程序只能在為該應(yīng)用程序創(chuàng)建的文件夾(也就是沙盒)內(nèi)訪問文件,不可以訪問其他沙盒內(nèi)的內(nèi)容(iOS已經(jīng)部分開放訪問)
- 所有的非代碼文件都保存在沙盒中,圖片、音頻、視頻、屬性列表(plist)、sqlite數(shù)據(jù)庫以及文本文件等。
沙盒機(jī)制的特點(diǎn)
- 每個應(yīng)用程序的活動范圍都限定在自己的沙盒里
- 不能隨意跨越自己的沙盒去訪問別的應(yīng)用程序沙盒的內(nèi)容(iOS8已經(jīng)部分開放訪問)
- 應(yīng)用程序想外請求或者接手?jǐn)?shù)據(jù)都需要經(jīng)過權(quán)限認(rèn)證
沙盒文件系統(tǒng)目錄
獲取某個模擬器下某個應(yīng)用程序沙盒的所在位置
/Users/用戶名/Library/Developer/CoreSimulator/Devices/6892D97C-37CD-4788-9EAF-DD65C0C5480C/data/Containers/Data/Application/85F0B633-0C22-4511-BCD8-3C531D9C9750
- PS1:上面的文件路徑就是一個應(yīng)用程序的沙盒所在位置,也就是沙盒的根目錄
- PS2:第一個粗體顯示的路徑是設(shè)備(模擬器)的路徑,第二個粗體顯示的路徑表示這個應(yīng)用程序沙盒的路徑
打開某個應(yīng)用程序的沙盒
- 三擊你的沙盒路徑(選中區(qū)域前后有多余的文字,并不會干擾接下來的操作,Mac系統(tǒng)會自動識別其中的文件路徑)
- 點(diǎn)擊鼠標(biāo)右鍵選擇Services
- 在Services的子選項(xiàng)中選擇Reveal in Finder
- PS:連續(xù)點(diǎn)擊三次鼠標(biāo)左鍵,選中光標(biāo)所在位置的行,雙擊選中光標(biāo)所在位置的單詞
應(yīng)用程序的沙盒目錄
應(yīng)用程序的沙盒目錄下?lián)碛腥齻€很特殊的文件夾分別是Documents、Library(擁有Caches和Preferences目錄)、tmp。
Documents:保存應(yīng)用程序運(yùn)行時生成的需要持久化數(shù)據(jù),iTunes會自動備份該目錄
蘋果公司建議將程序中建立的活在程序?yàn)g覽到的文件數(shù)據(jù)保存在該目錄下,iTunes備份和恢復(fù)的時候會包括此目錄
Library:存儲程序的默認(rèn)設(shè)置和其他狀態(tài)信息,iTunes會自動備份該文件目錄
- Library/Caches:存放緩存文件,iTunes不會備份此目錄,此目錄下文件不會在應(yīng)用退出時刪除,通常存放體積比較大,但并不是很重要的資源
- Library/Preferences:保存應(yīng)用的所有偏好設(shè)置,iOS的Setting(設(shè)置)應(yīng)用會在該目錄中查找應(yīng)用的設(shè)置信息,iTunes會自動備份該目錄?!狿S:如果你想對偏好設(shè)置進(jìn)行相應(yīng)的操作,應(yīng)該使用NSUserDefaults類來取得和設(shè)置應(yīng)用程序的偏好,而不是直接創(chuàng)建偏好設(shè)置文件
tmp:保存應(yīng)用程序運(yùn)行時所需的臨時數(shù)據(jù),使用完畢后再將相應(yīng)的文件從該目錄刪除,應(yīng)用沒有運(yùn)行時,系統(tǒng)也有可能會清除該目錄下的文件,iTunes不會同步該目錄,你的iPhone重啟時,該目錄下的文件會被刪除
獲取沙盒內(nèi)文件的路徑
// 獲取Documents目錄
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// 獲取tmp目錄
NSString *tmpPath = NSTemporaryDirectory();
// 獲取Library目錄
NSString *libPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
// 獲取Library/Caches目錄
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// 獲取Library/Preferences目錄
NSString *prePath = [NSSearchPathForDirectoriesInDomains(NSPreferencePanesDirectory, NSUserDomainMask, YES) lastObject];
//通常情況下,Preferences由系統(tǒng)維護(hù),我們很少去操作TA
// 獲取應(yīng)用程序包的路徑
NSString *path = [NSBundle mainBundle].resourcePath;
二、簡單對象的讀寫(I/O)操作#
簡單對象
iOS中提供四種類型可以直接進(jìn)行文件存?。?/p>
NSString(字符串)
NSArray(數(shù)組)
NSDictionary(字典)
NSData(數(shù)據(jù))
包括上述類型的子類
NSString的寫入與讀取
// 字符串寫入沙盒
// 在Documents下面創(chuàng)建一個文本路徑,假設(shè)文本名稱為objc.txt
NSString *txtPath = [docPath stringByAppendingPathComponent:@"objc.txt"]; // 此時僅存在路徑,文件并沒有真實(shí)存在
NSString *string = @"Objective-C";
// 字符串寫入時執(zhí)行的方法
[string writeToFile:txtPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSLog(@"txtPath is %@", txtPath);
// 字符串讀取的方法
NSString *resultStr = [NSString stringWithContentsOfFile:txtPath encoding:NSUTF8StringEncoding error:nil];
NSLog(@"resultStr is %@", resultStr);
NSArray的寫入與讀取
// 數(shù)組寫入文件
// 創(chuàng)建一個存儲數(shù)組的文件路徑
NSString *filePath = [docPath stringByAppendingPathComponent:@"language.txt"];
NSArray *array = @[@"C語言", @"JAVA",@"Objective-C", @"Swift", @"PHP", @"C++", @"C#"];
// 數(shù)組寫入文件執(zhí)行的方法
[array writeToFile:filePath atomically:YES];
NSLog(@"filePath is %@", filePath);
// 從文件中讀取數(shù)據(jù)數(shù)組的方法
NSArray *resultArr = [NSArray arrayWithContentsOfFile:filePath];
NSLog(@"%@", resultArr[1]);
NSDictionary的寫入與讀取
// 字典寫入文件
// 創(chuàng)建一個存儲字典的文件路徑
NSString *fileDicPath = [docPath stringByAppendingPathComponent:@"love.txt"];
NSDictionary *dic = @{@"職業(yè)":@"程序員", @"夢想":@"代碼無BUG"};
// 字典寫入時執(zhí)行的方法
[dic writeToFile:fileDicPath atomically:YES];
NSLog(@"fileDicPath is %@", fileDicPath);
// 從文件中讀取數(shù)據(jù)字典的方法
NSDictionary *resultDic = [NSDictionary dictionaryWithContentsOfFile:fileDicPath];
NSLog(@"%@", resultDic[@"夢想"]);
NSData的寫入與讀取
// NSData寫入文件
// 創(chuàng)建一個存放NSData數(shù)據(jù)的路徑
NSString *fileDataPath = [docPath stringByAppendingPathComponent:@"icon"];
// 得到一個UIImage對象
UIImage *image = [UIImage imageNamed:@"icon.jpg"];
// 將UIImage對象轉(zhuǎn)換成NSData對象
NSData *data = UIImageJPEGRepresentation(image, 0);
[data writeToFile:fileDataPath atomically:YES];
NSLog(@"fileDataPath is %@", fileDataPath);
// 從文件讀取存儲的NSData數(shù)據(jù)
NSData *resultData = [NSData dataWithContentsOfFile:fileDataPath];
// 將得到的NSData數(shù)據(jù)轉(zhuǎn)換成原有的圖片對象
UIImage *resultImage = [UIImage imageWithData:resultData];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
imageView.image = resultImage;
[self.view addSubview:imageView];
三、文件管理器與文件對接器#
文件管理器與文件連接器之間的區(qū)別
- 文件管理器主要是對文件進(jìn)行操作(創(chuàng)建、刪除、改名等)以及文件信息的獲取
- 文件連接器主要是對文件內(nèi)容進(jìn)行讀取與寫入操作
文件管理器
使用文件管理器創(chuàng)建文件夾
// 獲取到Caches文件夾路徑
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// 獲取創(chuàng)建文件夾的路徑
NSString *dirPath = [cachePath stringByAppendingPathComponent:@"testDirectroy"];
// 創(chuàng)建文件管理對象
NSFileManager *fileManager = [NSFileManager defaultManager];
// 創(chuàng)建文件夾
[fileManager createDirectoryAtPath:dirPath withIntermediateDirectories:YES attributes:nil error:nil];
NSLog(@"%@", dirPath);
通過文件管理器創(chuàng)建文件以及獲取文件信息
// 得到Documents路徑
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// 創(chuàng)建一個文件路徑
NSString *filePath = [docPath stringByAppendingPathComponent:@"objc.txt"];
// 創(chuàng)建文件首先需要一個文件管理對象
NSFileManager *fileManager = [NSFileManager defaultManager];
// 創(chuàng)建文件
[fileManager createFileAtPath:filePath contents:[@"Objective-C" dataUsingEncoding:NSUTF8StringEncoding] attributes:nil];
NSLog(@"%@",filePath);
// 獲取某個文件或者某個文件夾的大小
NSDictionary *dic = [fileManager attributesOfItemAtPath:filePath error:nil];
NSLog(@"%@", dic);
NSNumber *number = [dic objectForKey:NSFileSize];
NSInteger size = number.intValue;
NSLog(@"%@", number);
文件移動
// 創(chuàng)建文件夾
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *pathPath = [docPath stringByAppendingPathComponent:@"path"];
// 創(chuàng)建文件
NSString *path = [pathPath stringByAppendingPathComponent:@"test.txt"];
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *dirPath = [cachePath stringByAppendingPathComponent:@"testDirectroy"];
NSString *desPath = [dirPath stringByAppendingPathComponent:@"test.txt"];
// 創(chuàng)建文件管理器對象,進(jìn)行文件移動操作
NSFileManager *fileManager = [NSFileManager defaultManager];
// 移動文件
[fileManager moveItemAtPath:path toPath:desPath error:nil]; // 移動文件的核心代碼
文件對接器
/**
* 練習(xí)要求:從一個文件中指定的位置開始追加內(nèi)容
提示:
1、在documents目錄下創(chuàng)建一個test.txt文件,文件中的內(nèi)容為"abcdefg"
2、從文件偏移量為3那個位置開始追加內(nèi)容"1234"
*/
// 獲取Documents文件夾路徑
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// 創(chuàng)建文件路徑
NSString *filePath = [docPath stringByAppendingPathComponent:@"test.txt"];
// 使用文件管理對象創(chuàng)建文件
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager createFileAtPath:filePath contents:[@"abcdefg" dataUsingEncoding:NSUTF8StringEncoding] attributes:nil];
// 創(chuàng)建文件對接對象
NSFileHandle *handle = [NSFileHandle fileHandleForUpdatingAtPath:filePath]; // 文件對接對象此時針對文件既可以讀取又可以寫入
// 將偏移量挪到3的位置
[handle seekToFileOffset:3];
// 寫入數(shù)據(jù)
[handle writeData:[@"1234" dataUsingEncoding:NSUTF8StringEncoding]];
// 執(zhí)行完操作之后不要忘記關(guān)閉文件
[handle closeFile];
四、復(fù)雜對象的讀寫(I/O)操作#
復(fù)雜對象指的是在Foundation框架內(nèi)不存在的數(shù)據(jù)類,如自定以的Person類,像這種自定義的類是無法在程序內(nèi)部通過writeToFile:這個方法寫入到文件內(nèi)
既然復(fù)雜對象無法使用內(nèi)部方法進(jìn)行數(shù)據(jù)持久化,那么只能通過將復(fù)雜對象轉(zhuǎn)換成NSData,然后在通過上面的方法寫入文件,而這種轉(zhuǎn)換的步驟就被稱為歸檔,從文件中讀取NSData數(shù)據(jù),將NSData轉(zhuǎn)換為復(fù)雜對象,這個步驟就是反歸檔
記住
- 復(fù)雜對象寫入文件的過程(復(fù)雜對象->歸檔->NSData->writeToFile)
- 從文件中讀取出復(fù)雜對象過程(讀取文件->NSData->反歸檔->復(fù)雜對象)
- 首先,復(fù)雜對象所屬的類要遵守<NSCoding>
- 其次,實(shí)現(xiàn)協(xié)議中的兩個方法:
- -(void)encodeWithCoder:(NSCoder *)aCoder; 序列化
- -(id)initWithCoder:(NSCoder *)aDecoder; 反序列化
- 首先,遵守NSCoding協(xié)議
@interface Person:NSObject<NSCoding>
@property(nonatomic,copy) NSString *name
@property(nonatomic,assign) integer age;
@end
- 其次,實(shí)現(xiàn)協(xié)議中的兩個方法:
// 對person對象進(jìn)行歸檔時,此方法執(zhí)行。
// 對person中想要進(jìn)行歸檔的所有屬性,進(jìn)行序列化操作。
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeInteger:self.age forKey:@"age"];
}
// 對person對象進(jìn)行反歸檔時,該方法執(zhí)行。
// 創(chuàng)建一個新的person對象,所有屬性都是通過反序列化得到的。
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = [aDecoder decodeIntegerForKey:@"age"];
}
return self;
}
// 準(zhǔn)備一個NSMutableData, 用于保存歸檔后的對象
NSMutableData *data = [NSMutableData data];
// 創(chuàng)建歸檔工具
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingMutableData:data];
// 歸檔
[archiver encodeObject:p] forKey:@"p1"];
// 結(jié)束
[archiver finishEncoding];
// 拼音寫入沙盒路徑
NSString *caches = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
NSString *filePath = [caches stringByAppendingPathComPonent:@"person"];
// 寫入沙盒
[data writeToFile:filePath atomically:YES];
// 反歸檔
// 從filePath文件路徑讀取
NSData *data = [NSData dataWithContentsOfFile:filePath];
// 反歸檔工具
NSKeyedUnarchiver *unArchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
// 反歸檔成對象
Person *p2 = [unArchiver decodeObjectForKey:@"p1"];
// 反歸檔結(jié)束
[unArchiver finshDeoding];