谈谈ios沙盒机制和数据存储

iOS为每个应用提供了独立的文件空间,一个应用只能直接访问本应用分配的文件目录,不可以访问其他目录,每个应用自己独立的访问空间被称为该应用的沙盒。

一、 沙盒

在app被安装时,iOS会为应用创建三个容器,如
分别为Bundle Container和Data Container和iCloud Container。

iOS 8.0 之后,bundle 目录和沙盒目录 (Data) 是分开的。iOS 7.0 及以前版本 bundle 目录和沙盒目录 (Data) 是在一起的。

1. Bundle Container

MyApp.app :这就是应用的运行包(bundle),
bundle路径就是通常所说的应用程序在手机里面的安装路径,其就是一个目录,这个目录就是main bundle。这个目录里面通常包含图像、媒体资源、编译好的代码、nib、文件等可执行文件和所有资源文件,这个目录是只读的。

  // 获得 Bundle 信息
  /*
      通常指向 xxx.app/ 这个根目录
  */
  NSBundle *mainBundle = [NSBundle mainBundle];

  // 获取 Bundle 文件路径
  NSString *bundlePath = [NSBundle mainBundle].bundlePath;
  NSString *resourcePath = [NSBundle mainBundle].resourcePath;

  // 获取 Bundle URL 路径
  NSURL *bundleUrl = [NSBundle mainBundle].bundleURL;
  NSURL *resourceURL = [NSBundle mainBundle].resourceURL;

  // 获得 Bundle 目录下的文件路径
  NSString *filePath1 = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"txt"];

  // 获得 bundle 下子目录 subdirectory 下的文件路径
  NSString *filePath2 = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"txt" inDirectory:@"testFolder"];

  // 获得 Bundle 目录下的 URL 路径
  NSURL *fileUrl1 = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"txt"];

  // 获得 bundle 下子目录 subdirectory 下的 URL 路径
  NSURL *fileUrl2 = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"txt" subdirectory:@"testFolder"];

  // 获取应用程序唯一标识包名
  NSString *indentifier = [NSBundle mainBundle].bundleIdentifier;

  // 获取应用程序 Info.plist 配置项词典对象实例
  NSDictionary *info = [NSBundle mainBundle].infoDictionary;

  // 获取某一特定字段的内容
  NSString *bundleID = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];

  // 获取某bundle下的某个文件
  NSBundle *bundle = [NSBundle bundleWithPath:[[NSBundle  mainBundle] pathForResource:@"xxx" ofType:@"bundle"]];
  NSString *path = [bundle pathForResource:@"xxx" ofType:@"plist"];

2. Data Container

获取主目录路径

NSString * homePath = NSHomeDirectory();

可分为三个部分,Documents、Library、tmp。

如下图所示

2.1 Document

保存由用户产生的文件或者数据,苹果建议将程序中建立的或在程序中浏览到的文件数据保存在该目录下,iTunes备份和恢复的时候会包括此目录,该文件夹下的内容不会被系统自动删除,例如:例如一个日记应用中用户写的日记文件,或者音乐播放器中用户下载的歌曲。

// 获取 Document 路径
NSString * documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, 
TRUE).firstObject;
2.2 Library
 // 获取 Library 路径
 NSString *libraryPath = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, 
                                                                    NSUserDomainMask, 
                                                                    TRUE)
                                                                    .firstObject;
2.2.1 Library/Caches

用来存放缓存文件,保存从网络下载的请求数据,后续仍然需要继续使用的文件,例如网络下载的离线数据,图片,视频文件等。该目录中的文件系统不会自动删除,可以做离线访问。它的存放时间比 tmp 下的长,但是不如 Library 下的其它目录。总的来说 Caches 目录下存放的数据不能是应用程序运行所必需的,但是能提高应用访问性能的。可写入应用支持文件,保存应用程序再次启动需要的信息。iCloud不备份。

// 获取 Caches 路径
NSString *cachesPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, 
                                                                   NSUserDomainMask, 
                                                                   TRUE)
                                                                   .firstObject;
2.2.2 Library/Preferences

常用来放置配置文件、数据文件、模板等应用在运行中与用户相关,而又希望对用户不可见的文件,如系统偏好设置,用户偏好设置等文件。使用 NSUserDefaults 类进行偏好设置文件的创建、读取和修改。

2.3 temp

保存应用运行时产生的一些临时数据,应用程序退出,系统磁盘空间不够,手机重启时,都会自动清除该目录的数据。无需程序员手动清除该目录中的数据.iTunes、iCloud备份时,不会备份此目录

//获取临时文件路径
NSString *tempPath = NSTemporaryDirectory();
2.4 文件路径
 // 获取满足条件的路径列表
 NSArray<NSString *> * NSSearchPathForDirectoriesInDomains(
                                      NSSearchPathDirectory directory, 
                                      NSSearchPathDomainMask domainMask, 
                                      BOOL expandTilde);
  1. 参数:NSSearchPathDirectory 指定查找的目录范围
typedef NS_ENUM(NSUInteger, NSSearchPathDirectory) {
    NSApplicationDirectory = 1,             // supported applications (Applications)  应用程序
    NSDemoApplicationDirectory,             // unsupported applications, demonstration versions (Demos)
    NSDeveloperApplicationDirectory,        // developer applications (Developer/Applications). DEPRECATED - there is no one single Developer directory.  已弃用
    NSAdminApplicationDirectory,            // system and network administration applications (Administration)
###Library###
    NSLibraryDirectory,                     // various documentation, support, and configuration files, resources (Library)
    NSDeveloperDirectory,                   // developer resources (Developer) DEPRECATED - there is no one single Developer directory. 已弃用
    NSUserDirectory,                        // user home directories (Users)
    NSDocumentationDirectory,               // documentation (Documentation)
###Document###
    NSDocumentDirectory,                    // documents (Documents)
    NSCoreServiceDirectory,                 // location of CoreServices directory (System/Library/CoreServices)
    NSAutosavedInformationDirectory API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)) = 11,   // location of autosaved documents (Documents/Autosaved)
    NSDesktopDirectory = 12,                // location of user's desktop
###Caches###
    NSCachesDirectory = 13,                 // location of discardable cache files (Library/Caches)
    NSApplicationSupportDirectory = 14,     // location of application support files (plug-ins, etc) (Library/Application Support)
    NSDownloadsDirectory API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)) = 15,              // location of the user's "Downloads" directory
    NSInputMethodsDirectory API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)) = 16,           // input methods (Library/Input Methods)
    NSMoviesDirectory API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)) = 17,                 // location of user's Movies directory (~/Movies)
    NSMusicDirectory API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)) = 18,                  // location of user's Music directory (~/Music)
    NSPicturesDirectory API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)) = 19,               // location of user's Pictures directory (~/Pictures)
    NSPrinterDescriptionDirectory API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)) = 20,     // location of system's PPDs directory (Library/Printers/PPDs)
    NSSharedPublicDirectory API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)) = 21,           // location of user's Public sharing directory (~/Public)
    NSPreferencePanesDirectory API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)) = 22,        // location of the PreferencePanes directory for use with System Preferences (Library/PreferencePanes)
    NSApplicationScriptsDirectory NS_ENUM_AVAILABLE(10_8, NA) = 23,      // location of the user scripts folder for the calling application (~/Library/Application Scripts/code-signing-id)
    NSItemReplacementDirectory API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)) = 99,        // For use with NSFileManager's URLForDirectory:inDomain:appropriateForURL:create:error:
    NSAllApplicationsDirectory = 100,       // all directories where applications can occur
    NSAllLibrariesDirectory = 101,          // all directories where resources can occur
    NSTrashDirectory API_AVAILABLE(macos(10.8), ios(11.0)) API_UNAVAILABLE(watchos, tvos) = 102             // location of Trash directory
};
  1. NSSearchPathDomainMask 指定查找的文件系统域,可以是多值
typedef NS_OPTIONS(NSUInteger, NSSearchPathDomainMask) {
      ###UserDomain###
        NSUserDomainMask = 1,       // user's home directory --- place to install user's personal items (~) 当前用户的 home 目录
        NSLocalDomainMask = 2,      // local to the current machine --- place to install items available to everyone on this machine (/Library) //指向对所有用户可用的当前机器范围
        NSNetworkDomainMask = 4,    // publically available location in the local area network --- place to install items available on the network (/Network) 
        NSSystemDomainMask = 8,     // provided by Apple, unmodifiable (/System)
        NSAllDomainsMask = 0x0ffff  // all domains: all of the above and future items
    };
  1. expandTilde :指定是否展开路径中的代字符“~”,YES代表展开

数据存储

write to file 思路:先得到目录路径,然后write to file

1.基本数据类型,字符串、字典、数组等

比如我们在Document目录进行存储

- (NSString *)getDocumentFilePath
{
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString * documentDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, TRUE)[0];
    if (![fileManager fileExistsAtPath:documentDir]) {
    [fileManager createDirectoryAtPath:documentDir withIntermediateDirectories:YES attributes:nil error:nil];
    }
    return documentDir;
}

    //获取document目录路径
    NSString *documentPath = [self getDocumentFilePath];
    //创建一个test.txt路径
    NSString *testPath = [documentPath stringByAppendingPathComponent:@"test.txt"];
    NSString *content = @"这仅仅是测试";
    NSError * error;
    [content writeToFile:testPath atomically:TRUE encoding:NSUTF8StringEncoding error:&error];
    if (!error) {
         NSLog(@"写入数据成功");
    }else{
        NSLog(@"写入数据失败");
    } 
   
    /*
    NSData *data = [content dataUsingEncoding:NSUTF8StringEncoding];
    BOOL success = [data writeToFile:testPath atomically:TRUE];
    if (success) {
        NSLog(@"写入数据成功");
    }else{
       NSLog(@"写入数据失败");
   }
    */ 

读取数据

 //获取document目录路径
 NSString *documentPath = [self getDocumentFilePath];
 //创建一个test.txt路径
 NSString *testPath = [documentPath stringByAppendingPathComponent:@"test.txt"];
 NSString *str = [[NSString alloc]initWithContentsOfFile:testPath encoding:NSUTF8StringEncoding error:nil];

 // NSData *data = [NSData dataWithContentsOfFile:testPath];
 // NSString *str =  [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];

  NSLog(@"%@",str);
//存字典
NSDictionary *dict = @{@"key":@"这仅仅是测试"};
BOOL success = [dict writeToFile:testPath atomically:TRUE];

 //读字典
 NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:testPath];

  1. 自定义类的对象
    保存自定义的类对象,需要用到NSKeydeArchiver归档。必须使被归档的类遵守NSCoding协议并且实现协议方法。

下面以例子来说明

Person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject <NSCoding>

@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;

@end
Person.m

#import "Person.h"

@implementation Person

// 当一个对象要保存到文件中的时候回调用如下方法,所以重写该方法,说明保存该对象的时候要保存哪些属性。
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeInteger:self.age forKey:@"age"];
}

// 当一个对象从文件中读取的时候,系统会调用该方法,重写该方法
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
if ([super init]) {
    self.name = [aDecoder decodeObjectForKey:@"name"];
    self.age = [aDecoder decodeIntForKey:@"age"];
}
return self;
}

@end

Person *p = [[Person alloc] init];
p.name = @"joe";
p.age = 20;

//获取文件路径
NSString *docPath=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *path=[docPath stringByAppendingPathComponent:@"person.txt"];

//将自定义的对象保存到文件中
[NSKeyedArchiver archiveRootObject:p1 toFile:path];

//读取数据
Person *person =[NSKeyedUnarchiver unarchiveObjectWithFile:path];

NSUserDefaults

使用NSUserDefaults来保存数据, 会将所有的数据都保存到Preferences的文件夹下的同一个plist文件中。保存格式为plist文件格式。
使用偏好设置对数据进行保存, 它保存的时间是不确定的,会在将来某一时间自动将数据保存到Preferences文件夹下,如果需要即刻将数据存储,使用[defaults synchronize]。


// 获取NSUserDefaults对象
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

// 保存数据
[defaults setObject:@"这仅仅是测试" forKey:@"key"];

// 让数据立刻保存
[defaults synchronize];


//读取数据
NSString *test = [defaults objectForKey:@"test"];

如下图所示

CAC885C4-F5F2-4525-9461-338904E13862.png

SQLite

采用 SQLite 数据库来存储数据。SQLite 作为一中小型数据库,通常用来存储大量数据。但是进行操作时需要使用C语言的函数,比较麻烦。
FMDB是对SQLite3框架封装以OC的方式进行操作的第三方框架,相对于原生SQLite,使用起来更加方便,而且对于多线程的并发操作进行了处理,是线程安全的。

在项目中导入FMDB文件github地址或者pod 'FMDB'
然后导入libsqlite3.0框架和导入FMDB.h

下面我们以一个例子来说明

创建一个Student类和一个Cource类

@interface Student : NSObject<NSCoding>
@property (nonatomic, assign) NSInteger sId;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) NSArray *courses;
@end

@interface Course : NSObject<NSCoding>
@property (nonatomic, strong) NSString *name;
@end

因为Student类里包含自定义对象,所以存储时需要遵循NSCoding协议进行归档操作

@implementation student
- (id)initWithCoder:(NSCoder *)aDecoder{
    if (self = [super init]) {
        self.sId = [aDecoder decodeIntForKey:@"sId"];
        self.name = [aDecoder decodeObjectForKey:@"name"];
        self.courses = [aDecoder decodeObjectForKey:@"cources"];
    }
    return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder{
    [aCoder encodeInteger:self.sId forKey:@"sId"];
    [aCoder encodeObject:self.name forKey:@"name"];
    [aCoder encodeObject:self.courses forKey:@"cources"];
}
@end

@implementation Course

- (id)initWithCoder:(NSCoder *)aDecoder{
    if (self = [super init]) {
        self.name = [aDecoder decodeObjectForKey:@"name"];
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder{
    [aCoder encodeObject:self.name forKey:@"name"];
}
@end


数据库操作

//建数据库,建表

FMDatabase    *fmdb;
NSString      *_dbPath;

- (void)initDataBase{
    //获得documents目录路径
    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    //文件路径
    _dbPath = [documentPath stringByAppendingPathComponent:@"student.db"];
    //示例化FMDataBase对象
    NSLog(@"-----path:%@",_dbPath);
    fmdb = [FMDatabase databaseWithPath:_dbPath];
    if ([fmdb open]) {
        //初始化数据表
        [self addStudentTable];

    }else{
        NSLog(@"数据库打开失败---%@",fmdb.lastErrorMessage);
    }
}

//创建Student表格
- (void)addStudentTable{
    NSString *studentSql = @"create table if not exists student (id integer Primary Key Autoincrement, sId integer, name text, courses blob)";
    BOOL studentSuccess = [fmdb executeUpdate:studentSql];
   
    if (!studentSuccess) {
        NSLog(@"student表格创建失败---%@", fmdb.lastErrorMessage);
    }else{
        NSLog(@"student表格创建成功");
    }
}

//text 数据库中文本数据,blob 数据库中用来存储二进制文件的字段类型

//获取student表格全部数据
- (NSMutableArray *)getAllStudent{
   
     NSMutableArray * students = [[NSMutableArray alloc]init];
    
    if ([fmdb open]) {
        //查找student所有列表,按照id升序
        /*
        desc是descend 降序意思
        asc 是ascend 升序意思 默认
         */
        FMResultSet *result = [fmdb executeQuery:@"select * from student order by id desc"];
        while ([result next]) {
            Student *student  = [[Student alloc] init];
            student.sId = [[result stringForColumn:@"sId"] integerValue];
            student.name = [result stringForColumn:@"name"];
            student.courses = [self unarchivedObjectWithObject:data];
           
            [students addObject:student];
        }
    
         [fmdb close];
    }
    return students;

}

//根据学生id查找student信息
- (Student *)searchStudent:(NSString *)sId{
    if ([fmdb open]) {
        //通过名字查询学生信息
        
        NSString*sql = [NSString stringWithFormat:@"select * from student where sId = %ld ", sId.integerValue];

        FMResultSet  *result = [fmdb executeQuery:sql];

        while ([result next]) {

            Student*student = [[Student alloc] init];
            student.sId= [result intForColumn:@"sId"];
            student.name= [result stringForColumn:@"name"];
            student.courses = [self unarchivedObjectWithObject:data];

            [fmdb close];
            return  student;
        }
    }
    return nil;
}

//归档
- (id)archivedObjectWithObject:(id)object
{
    if (object == nil || object == [NSNull null]) {
        return nil;
    }
    return [NSKeyedArchiver archivedDataWithRootObject:object];
}
//解档
- (id)unarchivedObjectWithObject:(id)object
{
    if (object == nil || object == [NSNull null]) {
        return nil;
    }
    return [NSKeyedUnarchiver unarchiveObjectWithData:object];
}

//student表格添加内容
- (void)addStudent:(Student *)student{
    if ([fmdb open]) {
        NSString*sql =@"insert into student(sId,name,courses) values(?,?,?)";

        BOOL  isAddSuccess = [fmdb executeUpdate:sql,@(student.sId),student.name,[self archivedObjectWithObject:student.courses]];

        if (!isAddSuccess) {

            NSLog(@"student表格插入信息失败---%@",fmdb.lastErrorMessage);
        }else{
            NSLog(@"student表格插入信息成功!");
        }
        [fmdb close];
    }
}

//student表删除内容
- (void)deleteStudent:(Student *)student{

    if ([fmdb open]) {

        NSString *sql = @"delete from student where sId = ?";

        BOOL isDeleteSuccess = [fmdb executeUpdate:sql,@(student.sId)];

        if (!isDeleteSuccess) {

            NSLog(@"student表格删除信息失败---%@",fmdb.lastErrorMessage);
        }else{
            NSLog(@"student表格删除信息成功!");
        }
    }
}

//删除student表
- (void)deleteAllStudent{

    if ([fmdb open]) {

        NSString *sql = @"delete from student";

        BOOL isSuccess = [fmdb executeUpdate:sql];

        if (!isSuccess) {
            NSLog(@"student表格全部删除失败--%@",fmdb.lastErrorMessage);
        }else{
             NSLog(@"student表格全部删除成功! ");
        }
        [fmdb close];
       
    }
    
}

//student表修改内容
- (void)updateStudent:(Student *)student{
    if ([fmdb open]) {
     
        NSString*SQL =@"update student set name = ?, cources = ? where sId = ?";
        
        BOOL isSuccess = [fmdb executeUpdate: SQL, student.name,[self archivedObjectWithObject:student.courses]];
          
        if(!isSuccess) {
            
            NSLog(@"student修改失败--%@",fmdb.lastErrorMessage);
        }else{
            NSLog(@"student修改失败");
        }
        
      [fmdb close];
        
    }
}

项目中如果使用了多线程操作数据库,那么就需要使用FMDatabaseQueue来保证线程安全了。不可在多个线程中共同使用一个FMDatabase对象操作数据库,这样会引起数据库数据混乱。为了多线程操作数据库安全,FMDB使用了FMDatabaseQueue,首先用一个数据库文件地址来初使化FMDatabaseQueue,然后就可以将一个闭包(block)传入inDatabase方法中。 在闭包中操作数据库,而不直接参与FMDatabase的管理。

 FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:_dbPath];

再来看看查找所有Student

//获取student表格全部数据
- (NSMutableArray *)getAllStudent{
   
     NSMutableArray * students = [[NSMutableArray alloc]init];
 [queue inDatabase:^(FMDatabase * _Nonnull db) {
         if ([fmdb open]) {
        //查找student所有列表,按照id升序
        /*
        desc是descend 降序意思
        asc 是ascend 升序意思 默认
         */
        FMResultSet *result = [fmdb executeQuery:@"select * from student order by id desc"];
        while ([result next]) {
            Student *student  = [[Student alloc] init];
            student.sId = [[result stringForColumn:@"sId"] integerValue];
            student.name = [result stringForColumn:@"name"];
            student.courses = [self unarchivedObjectWithObject:data];
           
            [students addObject:student];
        }
    
         [fmdb close];
    }
 }];  
     
 return students;
   
}

结合GCD队列

- (void)addStudents:(NSArray *)students{
  
    for (int i = 0; i < students.count ;i ++) {

        const  char *queueName = [[NSString stringWithFormat:@"queque%d",i] UTF8String];

        dispatch_queue_t q = dispatch_queue_create(queueName, NULL);

        dispatch_async(q, ^{

            [queue inDatabase:^(FMDatabase * _Nonnull db) {

                Student *student = students[i];

                NSString *sql = @"insert into student (sId, name, cources) values (?,?,?)";

                BOOL isSuccess = [db executeUpdate:sql, @(student.sId),student.name,[self archivedObjectWithObject:student.courses]];

                if(!isSuccess) {

                    NSLog(@"studentTable插入信息失败--%@",db.lastErrorMessage);
                }else{
                    NSLog(@"studentTable插入信息成功!");
                }
            }];
        });
    }
    
}


三、文件管理

管理存储在沙盒中的文件,这时候需要用到NSFileManager了,
NSFileManager是iOS中的文件管理类。

 NSFileManager *manger = [NSFileManager defaultManager];

判断文件获取目录是否存在

NSString *documentPath = [self getDocumentFilePath];
NSString *filePath = [documentPath stringByAppendingPathComponent:@"test.txt"];
BOOL isExit1 = [manger fileExistsAtPath:filePath];

// isExit1为YES,说明test.txt这个文件是存在的

BOOL isDirectory;
BOOL isExit2 = [manger fileExistsAtPath:filePath isDirectory:&isDirectory];

// isExit2为YES,说明test.txt这个文件是存在的;
 isDirectory为NO,说明这个path是文件,而不是目录,当isDirectory为YES时,说明这个path是目录

创建目录或者文件

NSString *filePath = [documentPath stringByAppendingPathComponent:@"ceshi"];
NSError *error;
[manger createDirectoryAtPath:filePath withIntermediateDirectories:FALSE attributes:nil error:&error];
if (error) {
    NSLog(@"创建文件夹错误, error:%@",[error localizedDescription]);
}else{
    NSLog(@"创建文件夹成功");
 }
NSString *filePath = [documentPath stringByAppendingPathComponent:@"test1.txt"];
NSData *data = [@"这也是一个测试" dataUsingEncoding:NSUTF8StringEncoding];
[manger createFileAtPath:filePath contents:data attributes:nil];

然后我们看看沙盒里,果然是多了一个ceshi目录和test1.txt

删除文件

NSString *filePath = [documentPath stringByAppendingPathComponent:@"test1.txt"];
NSError *error;
[manger removeItemAtPath:filePath error:&error];

获取文件信息

  NSString *filePath = [documentPath stringByAppendingPathComponent:@"test.txt"];
  NSFileManager *manger = [NSFileManager defaultManager];
  NSError *error;
  NSDictionary *dict = [manger attributesOfItemAtPath:filePath error:&error];
  NSLog(@"%@",dict);

打印:
{
    NSFileCreationDate = "2017-08-14 10:40:14 +0000";
    NSFileExtendedAttributes =     {
        "com.apple.TextEncoding" = <7574662d 383b3133 34323137 393834>;
    };
    NSFileExtensionHidden = 0;
    NSFileGroupOwnerAccountID = 20;
    NSFileGroupOwnerAccountName = staff;
    NSFileModificationDate = "2017-08-14 10:40:14 +0000";
    NSFileOwnerAccountID = 501;
    NSFilePosixPermissions = 420;
    NSFileReferenceCount = 1;
    NSFileSize = 18;
    NSFileSystemFileNumber = 59320208;
    NSFileSystemNumber = 16777220;
    NSFileType = NSFileTypeRegular;
}

    NSFileSize(不可更改)
    文件或者文件夹的大小,注意单位是byte

    NSFileAppendOnly
    这个键的值需要设置为一个表示布尔值的NSNumber对象,表示创建的目录是否是只读的。

    NSFileCreationDate(可更改时间)
    这个键的值需要设置为一个NSDate对象,表示目录的创建时间。

    NSFileOwnerAccountName
    这个键的值需要设置为一个NSString对象,表示这个目录的所有者的名字。

    NSFileGroupOwnerAccountName
    这个键的值需要设置为一个NSString对象,表示这个目录的用户组的名字。

    NSFileGroupOwnerAccountID
    这个键的值需要设置为一个表示unsigned int的NSNumber对象,表示目录的组ID。

    NSFileModificationDate(可更改时间)
    这个键的值需要设置一个NSDate对象,表示目录的修改时间。

    NSFileOwnerAccountID
    这个键的值需要设置为一个表示unsigned int的NSNumber对象,表示目录的所有者ID。

    NSFilePosixPermissions
    这个键的值需要设置为一个表示short int的NSNumber对象,表示目录的访问权限。

    NSFileReferenceCount
    这个键的值需要设置为一个表示unsigned long的NSNumber对象,表示目录的引用计数,即这个目录的硬链接数

    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容