02、文件管理器、文件對接器與復雜對象的讀寫操作

一、文件管理器與文件連接器

1、文件管理器(NSFileManger),主要是對文件進行創建,刪除,改名以及文件信息的獲取操作。
以下是有關NSFileManger的方法

#pragma mark-------有關NSFileManager的方法
-(void)myFileManger{
    //獲取文件管理對象
    NSFileManager* fileManger=[NSFileManager defaultManager];
    //創建文件,并寫入數據 如果該方法的返回值為YES,文件創建成功或者文件已經存在  NO:文件創建失敗
    //第一個參數:要創建文件的路徑
    //第二個參數:要寫入文件的內容
    //第三個參數:設置文件的用戶組,權限,修改時間等設置,如果賦值為nil,系統就會自己為文件加一些默認設置
    //創建文件路徑
    NSString *path=[[SandBoxPaths cachesPath] stringByAppendingString:@"/array.json"];
    //創建要寫入的內容
    NSArray* array=@[@"王",@"余",@"雷"];
    NSData* arrayData=[NSJSONSerialization dataWithJSONObject:array options:(NSJSONWritingPrettyPrinted) error:nil];
    //判斷文件是否創建成功
   BOOL isSuccess= [fileManger createFileAtPath:path contents:arrayData attributes:nil];
    if (isSuccess) {
        NSLog(@"cachesPath-----%@",[SandBoxPaths cachesPath]);
    }
    else{
        NSLog(@"失敗");
    }
    
    //讀取數據
    //先判斷該路徑下文件是否存在
    BOOL isExists=[fileManger fileExistsAtPath:path];
    if (isExists) {
        //存在
        NSData* readData=[fileManger contentsAtPath:path];
        NSArray* readArray=[NSJSONSerialization JSONObjectWithData:readData options:(NSJSONReadingAllowFragments) error:nil];
        NSLog(@"讀取出來的----%@",readArray);
    }
    else{
        NSLog(@"該路徑下文件不存在");
    }
    
    //將cachesPath中的array.json文件移動到documents文件下  原有文件已經移動到了新的文件夾下,源文件已經不存在了.相當于剪切
    BOOL isMove=[fileManger moveItemAtPath:path toPath:[[SandBoxPaths documentPath] stringByAppendingString:@"/newarray.json"] error:nil];
    if (isMove) {
        NSLog(@"移動成功");
    }
    else{
        NSLog(@"失敗");
    }
    
    
    //將原有路徑下的文件拷貝到documents文件下,相當于復制
    BOOL isCopy=[fileManger copyItemAtPath:path toPath:[[SandBoxPaths documentPath] stringByAppendingString:@"/copyarray.json"] error:nil];
    if (isCopy) {
        NSLog(@"copy成功");
    }
    else{
        NSLog(@"失敗");
    }
    
    //比較文件內容
   BOOL isEqual= [fileManger contentsEqualAtPath:path andPath:[[SandBoxPaths documentPath] stringByAppendingString:@"/copyarray.json"]];
    if (isEqual) {
        NSLog(@"文件內容相同");
    }
    else{
        NSLog(@"文件內容不同");
    }
    
    BOOL isRemove=[fileManger removeItemAtPath:[[SandBoxPaths documentPath] stringByAppendingString:@"/copyarray.json"] error:nil];
    if (isRemove) {
        NSLog(@"刪除成功");
    }
    else{
        NSLog(@"失敗");
    }
    //創建文件夾
    // 第一個參數:要創建的文件夾的路徑
    //第二個參數:YES:如果父目錄(文件夾)不存在,創建的時候會將父目錄一起創建;NO:如果父目錄不存在,那么文件夾就會創建失敗
    //第三個參數: 文件夾的權限
   BOOL isCreat = [fileManger createDirectoryAtPath:[[SandBoxPaths homePath] stringByAppendingString:@"/newPath/aaa"] withIntermediateDirectories:YES attributes:nil error:nil];
    if (isCreat) {
        NSLog(@"創建成功");
    }
    else{
        NSLog(@"失敗");
    }
}

2、文件連接器(NSFileHandle),主要是對文件的內容進行讀取、寫入和更新操作。主要應用場景在對文件的內容進行局部修改,替換某些內容,有些地方說是追加內容,但我試了好幾遍,驗證了seekToFileOffset該方法是在指定偏移量后進行替換該位置的內容,而不是追加,望各位簡友多多注意這一點。
以下是有關NSFileHandle的方法

#pragma mark-------有關NSFileHandle的方法
//NSFileHandle的使用
-(void)myFileHandle{
   //獲取文件管理對象
   NSFileManager* manger=[NSFileManager defaultManager];
   NSString* path=[[SandBoxPaths documentPath] stringByAppendingString:@"/text.txt"];
   BOOL isExists=[manger fileExistsAtPath:path];
   if (!isExists) {
      //文件不存在,則創建
       [manger createFileAtPath:path contents:nil attributes:nil];
   }
  //對文件內容進行操作
  // 向文件寫入內容
     NSFileHandle* handle=[NSFileHandle fileHandleForWritingAtPath:path];
   NSString* inputString=@"yufei";
   NSData* inputData=[inputString dataUsingEncoding:NSUTF8StringEncoding];
   [handle writeData:inputData];
   //操作完畢要關閉文件
   [handle closeFile];

   //更新數據
   NSFileHandle* updateHandle=[NSFileHandle fileHandleForUpdatingAtPath:path];
   //我們要從余之后寫入數據,我們就需要將文件偏移量設置為1,然后再寫入。相當于從1位置開始將后面的字符或內容進行替換
   [updateHandle seekToFileOffset:1];
   NSString* updateString=@".qqq";
   NSData* updateData=[updateString dataUsingEncoding:NSUTF8StringEncoding];
   [updateHandle writeData:updateData];
     //操作完畢要關閉文件
   [updateHandle closeFile];
   
   //讀取數據
   NSFileHandle* readHandle=[NSFileHandle fileHandleForReadingAtPath:path];
   //設置要讀取多長的內容
//    NSData* readData=[readHandle readDataOfLength:3];
   NSData* readData=[readHandle readDataToEndOfFile];
    [readHandle closeFile];
   NSString* readString=[[NSString alloc] initWithData:readData encoding:NSUTF8StringEncoding];
   NSLog(@"readString---%@",readString);

   
}

該代碼中還差一些方法,我已經截圖給大家了,若對各位有幫助可以看一下

屏幕快照 2016-12-08 下午7.35.10.png

屏幕快照 2016-12-08 下午7.35.33.png

*兩者的區別就是NSFileManger針對文件進行操作,而NSFileHandle則針對文件中的內容進行操作。

二、復雜對象的讀寫操作

1、首先我們需要明白什么是復雜對象,簡單來說就是在Foundation框架內不存在的數據類,比如:自定義的Person類,Student類都屬于復雜對象,如果想要將這些類通過writeToFile方法寫入到文件夾內是不可以的,那么應該怎么辦呢,這就需要歸檔與反歸檔了。

  • 歸檔:就是將復雜對象轉換為NSData以達到數據持久化的目的,這就是歸檔,本質就是將復雜對象寫入文件。
  • 反歸檔:就是從文件中讀取NSData數據,將NSData轉換為復雜對象,這就是反歸檔,本質就是讀取文件的過程。
    在這里給大家做一個示范,請看下面的代碼

先在工程中將一個Person類,在Person.h中遵循協議,并聲明兩個屬性。


屏幕快照 2016-12-08 下午7.51.00.png

然后在Person.m實現協議里面的兩個方法

@implementation Person
//歸檔的過程,相當于將復雜對象轉換為NSData類型,是為了寫入文件
-(void)encodeWithCoder:(NSCoder *)aCoder{
    //歸檔的過程是將當前對象每一個屬性都進行編碼
    //第一個參數:要進行編碼的屬性的值
    //第二個參數:為屬性的值添加標記,是為了解碼使用
    [aCoder encodeObject:self.name forKey:@"name"];
    [aCoder encodeInteger:self.age forKey:@"age"];
    NSLog(@"執行了歸檔的方法");
}
//反歸檔的過程,相當于將NSData轉換為復雜對象,是為了讀取使用
//也是一個初始化方法
-(id)initWithCoder:(NSCoder *)aDecoder{
    NSLog(@"執行了反歸檔的方法");

    self=[super init];
    if (self) {
        //解碼  從文件中讀取出來值,賦值給對應的屬性
        self.name=[aDecoder decodeObjectForKey:@"name"];
        self.age=[aDecoder decodeIntegerForKey:@"age"];
    }
    return self;
}
@end

然后在ViewController.m中進行歸檔與反歸檔操作

//歸檔的過程
-(void)myEncoder{
   //需要創建一個Person對象
   Person* person=[[Person alloc] init];
   person.name=@"余菲";
   person.age=18;
   //需要創建一個可變的NSData對象,用來存放歸檔好的person對象
   NSMutableData* mData=[NSMutableData data];
   //創建一個歸檔工具
   //參數為要承接歸檔完成的復雜對象
   NSKeyedArchiver* archiver=[[NSKeyedArchiver alloc] initForWritingWithMutableData:mData];
   //歸檔
   //第一個參數:要歸檔的復雜對象
   //第二個參數:標記,為了反歸檔使用
   [archiver encodeObject:person forKey:@"person"];
   //歸檔結束,一定要調用下面這個方法,要不然mData中不會有值
   [archiver finishEncoding];
   //將mData持久化到本地
   NSString* Path=[[SandBoxPaths documentPath] stringByAppendingPathComponent:@"person.data"];
   [mData writeToFile:Path atomically:YES];
   NSLog(@"---%@",mData);
}
// 反歸檔的過程
-(void)myDecode{
    //將剛才歸檔文件的data數據讀取出來,以便反歸檔使用
     NSString* Path=[[SandBoxPaths documentPath] stringByAppendingPathComponent:@"person.data"];
    NSData* data=[NSData dataWithContentsOfFile:Path];
    //初始化一個反歸檔對象
    //參數:要反歸檔的data對象
    NSKeyedUnarchiver* unarchiver=[[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    //反歸檔
    Person* per_1=[unarchiver decodeObjectForKey:@"person"];
    // 反歸檔結束的方法,必須調用
    [unarchiver finishDecoding];
    NSLog(@"name---%@,age---%ld",per_1.name,(long)per_1.age);
        
}
  • 在這里面需要注意的就是在歸檔與反歸檔操作完成之后一定要記得調用finishDecoding方法結束操作。
  • 在這里有些人會問,為什么不直接將復雜對象的類進行歸檔呢,而是要對其中的一個個屬性進行編碼呢?有可能大家會忽略一點,那就是有些屬性也會是一個復雜對象,這時就會出現問題,所以歸檔時必須將當前對象每一個屬性都進行編碼,而在反歸檔時,必須挨個解碼。

在這里給大家簡單的提一下NSUserDefaults

 //NSUserDefaults 存儲到prefenrences文件夾下,在該文件夾下以plist格式存在 只能存儲簡單對象!!!!
    [[NSUserDefaults standardUserDefaults] setObject:@"余菲" forKey:@"name"];
    NSDictionary* dic=@{@"特點":@"乖巧可愛",@"年齡":@"芳齡18"};
    [[NSUserDefaults standardUserDefaults] setObject:dic forKey:@"property"];
    //刪除
//    [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"property"];
    //獲取存儲的值
    NSString* name=[[NSUserDefaults standardUserDefaults] objectForKey:@"name"];
    NSLog(@"name---%@",name);
    NSLog(@"preferencesPath-----%@",[SandBoxPaths  preferencesPath]);
屏幕快照 2016-12-08 下午8.06.40.png

希望對各位簡友有所幫助-----

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容