iOS進(jìn)階——數(shù)據(jù)處理之文件讀寫

一、沙盒機(jī)制#

沙盒的概念:沙盒是每一個iOS應(yīng)用程序都會自動創(chuàng)建的一個文件系統(tǒng)目錄(文件夾),而且沙盒還具有獨(dú)立、封閉、安全的特點(diǎn)。


沙盒機(jī)制

  1. iOS中的沙盒不僅僅是一個文件目錄,TA其實(shí)更是一種安全體系
  2. TA規(guī)定了應(yīng)用程序只能在為該應(yīng)用程序創(chuàng)建的文件夾(也就是沙盒)內(nèi)訪問文件,不可以訪問其他沙盒內(nèi)的內(nèi)容(iOS已經(jīng)部分開放訪問)
  3. 所有的非代碼文件都保存在沙盒中,圖片、音頻、視頻、屬性列表(plist)、sqlite數(shù)據(jù)庫以及文本文件等。

沙盒機(jī)制的特點(diǎn)

  1. 每個應(yīng)用程序的活動范圍都限定在自己的沙盒里
  2. 不能隨意跨越自己的沙盒去訪問別的應(yīng)用程序沙盒的內(nèi)容(iOS8已經(jīng)部分開放訪問)
  3. 應(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)用程序的沙盒

  1. 三擊你的沙盒路徑(選中區(qū)域前后有多余的文字,并不會干擾接下來的操作,Mac系統(tǒng)會自動識別其中的文件路徑)
  2. 點(diǎn)擊鼠標(biāo)右鍵選擇Services
  3. 在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會自動備份該文件目錄

  1. Library/Caches:存放緩存文件,iTunes不會備份此目錄,此目錄下文件不會在應(yīng)用退出時刪除,通常存放體積比較大,但并不是很重要的資源
  2. 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ù)雜對象)
  1. 首先,復(fù)雜對象所屬的類要遵守<NSCoding>
  1. 其次,實(shí)現(xiàn)協(xié)議中的兩個方法:
  • -(void)encodeWithCoder:(NSCoder *)aCoder; 序列化
  • -(id)initWithCoder:(NSCoder *)aDecoder; 反序列化
  1. 首先,遵守NSCoding協(xié)議
@interface Person:NSObject<NSCoding> 
      @property(nonatomic,copy) NSString *name 
      @property(nonatomic,assign) integer age; 
@end 
  1. 其次,實(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];
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容