iOS進階——數據處理之文件讀寫

一、沙盒機制#

沙盒的概念:沙盒是每一個iOS應用程序都會自動創建的一個文件系統目錄(文件夾),而且沙盒還具有獨立、封閉、安全的特點。


沙盒機制

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

沙盒機制的特點

  1. 每個應用程序的活動范圍都限定在自己的沙盒里
  2. 不能隨意跨越自己的沙盒去訪問別的應用程序沙盒的內容(iOS8已經部分開放訪問)
  3. 應用程序想外請求或者接手數據都需要經過權限認證

沙盒文件系統目錄
獲取某個模擬器下某個應用程序沙盒的所在位置

/Users/用戶名/Library/Developer/CoreSimulator/Devices/6892D97C-37CD-4788-9EAF-DD65C0C5480C/data/Containers/Data/Application/85F0B633-0C22-4511-BCD8-3C531D9C9750

  • PS1:上面的文件路徑就是一個應用程序的沙盒所在位置,也就是沙盒的根目錄
  • PS2:第一個粗體顯示的路徑是設備(模擬器)的路徑,第二個粗體顯示的路徑表示這個應用程序沙盒的路徑

打開某個應用程序的沙盒

  1. 三擊你的沙盒路徑(選中區域前后有多余的文字,并不會干擾接下來的操作,Mac系統會自動識別其中的文件路徑)
  2. 點擊鼠標右鍵選擇Services
  3. 在Services的子選項中選擇Reveal in Finder
  • PS:連續點擊三次鼠標左鍵,選中光標所在位置的行,雙擊選中光標所在位置的單詞

應用程序的沙盒目錄
應用程序的沙盒目錄下擁有三個很特殊的文件夾分別是Documents、Library(擁有Caches和Preferences目錄)、tmp。

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

Library:存儲程序的默認設置和其他狀態信息,iTunes會自動備份該文件目錄

  1. Library/Caches:存放緩存文件,iTunes不會備份此目錄,此目錄下文件不會在應用退出時刪除,通常存放體積比較大,但并不是很重要的資源
  2. Library/Preferences:保存應用的所有偏好設置,iOS的Setting(設置)應用會在該目錄中查找應用的設置信息,iTunes會自動備份該目錄。——PS:如果你想對偏好設置進行相應的操作,應該使用NSUserDefaults類來取得和設置應用程序的偏好,而不是直接創建偏好設置文件

tmp:保存應用程序運行時所需的臨時數據,使用完畢后再將相應的文件從該目錄刪除,應用沒有運行時,系統也有可能會清除該目錄下的文件,iTunes不會同步該目錄,你的iPhone重啟時,該目錄下的文件會被刪除


獲取沙盒內文件的路徑

// 獲取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由系統維護,我們很少去操作TA

// 獲取應用程序包的路徑
NSString *path = [NSBundle mainBundle].resourcePath;

二、簡單對象的讀寫(I/O)操作#

簡單對象
iOS中提供四種類型可以直接進行文件存取:

NSString(字符串)

NSArray(數組)

NSDictionary(字典)

NSData(數據)

  • 包括上述類型的子類

NSString的寫入與讀取

    // 字符串寫入沙盒
    // 在Documents下面創建一個文本路徑,假設文本名稱為objc.txt
    NSString *txtPath = [docPath stringByAppendingPathComponent:@"objc.txt"]; // 此時僅存在路徑,文件并沒有真實存在
    NSString *string = @"Objective-C";

    // 字符串寫入時執行的方法
    [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的寫入與讀取

    // 數組寫入文件
    // 創建一個存儲數組的文件路徑
    NSString *filePath = [docPath stringByAppendingPathComponent:@"language.txt"];
    NSArray *array = @[@"C語言", @"JAVA",@"Objective-C", @"Swift", @"PHP", @"C++", @"C#"];
    // 數組寫入文件執行的方法
    [array writeToFile:filePath atomically:YES];
    NSLog(@"filePath is %@", filePath);
    
    // 從文件中讀取數據數組的方法
    NSArray *resultArr = [NSArray arrayWithContentsOfFile:filePath];
    NSLog(@"%@", resultArr[1]);

NSDictionary的寫入與讀取

    // 字典寫入文件
    // 創建一個存儲字典的文件路徑
    NSString *fileDicPath = [docPath stringByAppendingPathComponent:@"love.txt"];
    NSDictionary *dic = @{@"職業":@"程序員", @"夢想":@"代碼無BUG"};
    
    // 字典寫入時執行的方法
    [dic writeToFile:fileDicPath atomically:YES];
    NSLog(@"fileDicPath is %@", fileDicPath);
    
    // 從文件中讀取數據字典的方法
    NSDictionary *resultDic = [NSDictionary dictionaryWithContentsOfFile:fileDicPath];
    NSLog(@"%@", resultDic[@"夢想"]);

NSData的寫入與讀取

    // NSData寫入文件
    // 創建一個存放NSData數據的路徑
    NSString *fileDataPath = [docPath stringByAppendingPathComponent:@"icon"];
    
    // 得到一個UIImage對象
    UIImage *image = [UIImage imageNamed:@"icon.jpg"];
    
    // 將UIImage對象轉換成NSData對象
    NSData *data = UIImageJPEGRepresentation(image, 0);
    [data writeToFile:fileDataPath atomically:YES];
    NSLog(@"fileDataPath is %@", fileDataPath);
    
    // 從文件讀取存儲的NSData數據
    NSData *resultData = [NSData dataWithContentsOfFile:fileDataPath];
    // 將得到的NSData數據轉換成原有的圖片對象
    UIImage *resultImage = [UIImage imageWithData:resultData];
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
    imageView.image = resultImage;
    [self.view addSubview:imageView];

三、文件管理器與文件對接器#

文件管理器與文件連接器之間的區別

  • 文件管理器主要是對文件進行操作(創建、刪除、改名等)以及文件信息的獲取
  • 文件連接器主要是對文件內容進行讀取與寫入操作

文件管理器

使用文件管理器創建文件夾

    // 獲取到Caches文件夾路徑
    NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    
    // 獲取創建文件夾的路徑
    NSString *dirPath = [cachePath stringByAppendingPathComponent:@"testDirectroy"];
    
    // 創建文件管理對象
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    // 創建文件夾
    [fileManager createDirectoryAtPath:dirPath withIntermediateDirectories:YES attributes:nil error:nil];
    
    NSLog(@"%@", dirPath);

通過文件管理器創建文件以及獲取文件信息

    // 得到Documents路徑
    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    
    // 創建一個文件路徑
    NSString *filePath = [docPath stringByAppendingPathComponent:@"objc.txt"];
    
    // 創建文件首先需要一個文件管理對象
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    // 創建文件
    [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);

文件移動

    // 創建文件夾
    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *pathPath = [docPath stringByAppendingPathComponent:@"path"];

    // 創建文件
    NSString *path = [pathPath stringByAppendingPathComponent:@"test.txt"];
    NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSString *dirPath = [cachePath stringByAppendingPathComponent:@"testDirectroy"];
    NSString *desPath = [dirPath stringByAppendingPathComponent:@"test.txt"];

    // 創建文件管理器對象,進行文件移動操作
    NSFileManager *fileManager = [NSFileManager defaultManager];

    // 移動文件
    [fileManager moveItemAtPath:path toPath:desPath error:nil]; // 移動文件的核心代碼


文件對接器

/**
 *  練習要求:從一個文件中指定的位置開始追加內容
 提示:
 1、在documents目錄下創建一個test.txt文件,文件中的內容為"abcdefg"
 2、從文件偏移量為3那個位置開始追加內容"1234"
 */

    // 獲取Documents文件夾路徑
    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    
    // 創建文件路徑
    NSString *filePath = [docPath stringByAppendingPathComponent:@"test.txt"];
    
    // 使用文件管理對象創建文件
    NSFileManager *fileManager = [NSFileManager defaultManager];
    [fileManager createFileAtPath:filePath contents:[@"abcdefg" dataUsingEncoding:NSUTF8StringEncoding] attributes:nil];
    
    // 創建文件對接對象
    NSFileHandle *handle = [NSFileHandle fileHandleForUpdatingAtPath:filePath]; // 文件對接對象此時針對文件既可以讀取又可以寫入
    
    // 將偏移量挪到3的位置
    [handle seekToFileOffset:3];
    
    // 寫入數據
    [handle writeData:[@"1234" dataUsingEncoding:NSUTF8StringEncoding]];
    
    // 執行完操作之后不要忘記關閉文件
    [handle closeFile];

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

復雜對象指的是在Foundation框架內不存在的數據類,如自定以的Person類,像這種自定義的類是無法在程序內部通過writeToFile:這個方法寫入到文件內
既然復雜對象無法使用內部方法進行數據持久化,那么只能通過將復雜對象轉換成NSData,然后在通過上面的方法寫入文件,而這種轉換的步驟就被稱為歸檔,從文件中讀取NSData數據,將NSData轉換為復雜對象,這個步驟就是反歸檔

記住

  • 復雜對象寫入文件的過程(復雜對象->歸檔->NSData->writeToFile)
  • 從文件中讀取出復雜對象過程(讀取文件->NSData->反歸檔->復雜對象)
  1. 首先,復雜對象所屬的類要遵守<NSCoding>
  1. 其次,實現協議中的兩個方法:
  • -(void)encodeWithCoder:(NSCoder *)aCoder; 序列化
  • -(id)initWithCoder:(NSCoder *)aDecoder; 反序列化
  1. 首先,遵守NSCoding協議
@interface Person:NSObject<NSCoding> 
      @property(nonatomic,copy) NSString *name 
      @property(nonatomic,assign) integer age; 
@end 
  1. 其次,實現協議中的兩個方法:
// 對person對象進行歸檔時,此方法執行。
// 對person中想要進行歸檔的所有屬性,進行序列化操作。
-(void)encodeWithCoder:(NSCoder *)aCoder
{
  [aCoder encodeObject:self.name forKey:@"name"];
  [aCoder encodeInteger:self.age forKey:@"age"];
}
// 對person對象進行反歸檔時,該方法執行。
// 創建一個新的person對象,所有屬性都是通過反序列化得到的。
-(id)initWithCoder:(NSCoder *)aDecoder 
{
  self = [super init];
  if (self) {
    self.name = [aDecoder decodeObjectForKey:@"name"];
    self.age = [aDecoder decodeIntegerForKey:@"age"];
  }
  return self;
}

// 準備一個NSMutableData, 用于保存歸檔后的對象
NSMutableData *data = [NSMutableData data];
// 創建歸檔工具
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingMutableData:data];
// 歸檔
[archiver encodeObject:p] forKey:@"p1"];
// 結束
[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"];
// 反歸檔結束
[unArchiver finshDeoding];
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容