dddd0427 沙河机制
dddd0427
/
// ViewController.m
// 沙盒机制
//
//
#import "ViewController.h"
#import "SingleVip.h"
#define IMG_URL @"http://news.eastday.com/images/thumbnailimg/month_1511/201511170142052896.jpg"
/**
* 数据持久化的本质:数据保存成二进制⽂文件,存储到程序的沙盒中。
*/
@interface ViewController ()
@end
@implementation ViewController
/**
*
iOS的沙盒机制,应用只能访问自己应用目录下的文件。iOS不像android,没有SD卡概念,不能直接访问图像、视频等内容。iOS应用产生的内容,如图像、文件、缓存内容等都必须存储在自己的沙盒内。默认情况下,每个沙盒含有3个文件夹:Documents, Library 和 tmp。Library包含Caches、Preferences目录。
文件结构图:
路径1----> Document
路径1----> Library---> Caches
---> Preferences
路径1----> Temp
路径2----> .app包(一个包含了 nib文件, 编译代码, 以及其他资源 的目录)
Documents:苹果建议将程序创建产生的文件以及应用浏览产生的文件数据保存在该目录下,iTunes备份和恢复的时候会包括此目录
Library:存储程序的默认设置或其它状态信息;
Library/Caches:存放缓存文件,保存应用的持久化数据,用于应用升级或者应用关闭后的数据保存,不会被itunes同步,所以为了减少同步的时间,可以考虑将一些比较大的文件而又不需要备份的文件放到这个目录下。
tmp:提供一个即时创建临时文件的地方,但不需要持久化,在应用关闭后,该目录下的数据将删除,也可能系统在程序不运行的时候清除。
*/
- (void)viewDidLoad {
[super viewDidLoad];
#pragma mark ------沙盒机制
/*
//沙盒主路径
//程序运行期间,系统会生成一个专属的沙盒路径,应用程序在使用期间的代码文件都会存储在当前的沙河路径里面
NSString *homePath = NSHomeDirectory();
NSLog(@"------应用程序目录的路径 :%@",homePath);
//上面的代码得到的是应用程序目录的路径,在该目录下有三个文件夹:Documents、Library、temp以及一个.app包!
//该目录下就是应用程序的沙盒,应用程序只能访问该目录下的文件夹!!!
#pragma mark ------ documents文件 :用来存储 永久性 的数据文件,程序运行时必要的文件都存在这里(数据库),iTunes会自动备份这里面的文件(documents library temp .app包(iOS8之前在之后就不在了) 在同一个文件夹里)
//第一个参数:要查询的文件的路径
//第二个参数:要查询路径所属的用户(iOS为单用户)
//第三个参数: YES 是绝对路径 NO 是相对路径
//区别于osX,iOS应用文件夹中通常只有一个文件路径
//由于OC同时支持苹果系列产品的开发,在Mac OS里,会同时存在很多软件,生成的路径放在一个数组里面
//iOS端一次只能有一个应用,所以取数组的唯一一个元素即可
NSArray *documentPathArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSLog(@"-------数组首元素地址%@",documentPathArray);//打印的是数组首元素地址(document的地址)
NSString *documentPath = [documentPathArray firstObject];
NSLog(@"------ documents文件 :%@",documentPath);//与上边地址为同一地址
#pragma mark ------ library文件 :用于保存程序运行期间生成的文件(下级文件: caches Preferences)
NSString *librarayPath = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES).firstObject;
NSLog(@"------ library文件 :%@",librarayPath);
#pragma mark ------caches文件 :用于保存程序运行期间产生的缓存文件
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)firstObject];
NSLog(@"------ caches文件 :%@",cachesPath);
#pragma mark ----preferences文件 :用来保存程序偏好设置
// NSString *preferencesPath = [NSSearchPathForDirectoriesInDomains(NSPreferencePanesDirectory, NSUserDomainMask, YES)firstObject];
//
// NSLog(@"---- preferences文件 :%@",preferencesPath);
//通过上面方法打印出来的路径,多了pane,所以,我们需要使用拼接字符串的方法,找到Preferences文件路径(找到上一级文件路径然后拼接 /Preferences)
//单例 NSUserDefaults,通常情况下,我们并不直接打开这个文件夹,而是通过NSUserDefaults进行偏好设置的存取
NSString *preferencesPath = [librarayPath stringByAppendingString:@"/Preferences"];
NSLog( @"------ preferences文件 :%@",preferencesPath);
#pragma mark ------ tmp临时文件夹 :程序运行期间产生的临时碎片会保存在这个文件夹里,通常文件下载完之后或者程序退出会自动清空此文件夹,iTunes不会备份这里的数据
//tips: 由于系统会清空此文件,所以下载或者其他临时文件若需要持久化要及时一走
NSString *tmpPath = NSTemporaryDirectory();
NSLog(@"------ tmp临时文件夹 :%@",tmpPath);
#pragma mark ======= .app路径(bundle)
//iOS8之前,bundle和tmp文件统一放在主路径下(home)
//iOS8之后,bundle放在了container文件夹下
NSString *bundle = [[NSBundle mainBundle] resourcePath];
NSLog(@"------程序中 文件,代码 的存储路径 :%@",bundle);
NSString *imagePath =[[NSBundle mainBundle]pathForResource:@"10" ofType:@"png"];
NSLog(@"-------程序中 图片 的存储路径 :%@",imagePath);
// NSBundle 类,直接继承NSObject类。
// 这个类的对象,代表了 app 中 代码和资源 的文件在文件系统里所在的位置,通俗的说,就是定位了程序使用的资源(代码,图形,音乐等数据)在文件系统里的位置,并可以动态的加载、or卸载掉可执行代码。
// 我们的程序是一个bundle. 在Finder中,一个应用程序看上去和其他文件没有什么区别. 但是实际上它是一个包含了 nib文件, 编译代码, 以及其他资源 的目录. 我们把这个目录叫做程序的mainBundle,在 xcode 里,使用 应用程序、框架、or 插件的时候,xcode 会生成对应的资源的目录包。
*/
#pragma mark ======== 简单对象写入文件)(NSString, NSArray, NSDictionary, NSData)
/*
#pragma mark ----- NSString写入文件
//1.准备字符串
NSString *string = @"I Love iOS teacher!";
//2.准备路径
NSString *path = NSHomeDirectory();
path = [path stringByAppendingString:@"/咒语.txt"];
//3.写入文件
//第一个参数:路径
//第二个参数:是否进行线性操作( YES 时保证发生意外时有中转文件来保存信息,直至写入完成,但是损耗大,NO 的时候写入速度快,但是没有安全保障)
//第三个参数:编码方式
//第四个参数:错误对象
[string writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
//4.打印路径
NSLog(@"-------I Love iOS teacher!存储路径 :%@",path);
//5.读取文件
//第一个参数:路径
//第二个参数:编码方式(切记要和写入时用相同的编码方式)
//第三个参数:错误信息
NSString *contentString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
NSLog(@"---------读取NSString :%@",contentString);
#pragma mark ----- NSArray写入文件
//1.准备数组
NSArray *array = [NSArray arrayWithObjects:@"lily",@"Yucui",@"Star",@"Ling",@"WenQi",@"Yangyang", nil];
//2.准备路径
NSString *docuPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)firstObject];
docuPath = [docuPath stringByAppendingString:@"/Lady.txt"];
//3.写入文件
[array writeToFile:docuPath atomically:YES];
//4.打印路径
NSLog(@"------数组存储 :%@",docuPath);
//5.读取文件
NSArray *aarray = [NSArray arrayWithContentsOfFile:docuPath];
NSLog(@"----- 读取NSArray:%@",aarray);
#pragma mark ----- NSDictionary写入文件
//1.准备字典
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:@"Zhangsan",@"One",@"Lisi",@"Two", nil];
//2.准备路径
NSString *libraraPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)firstObject];
NSString * preferencePath = [libraraPath stringByAppendingString:@"/Preferences/people.txt"];//需要使用拼接字符串的方法,找到Preferences文件路径(找到上一级文件路径然后拼接/Preferences
//3.写入文件
[dic writeToFile:preferencePath atomically:YES];
//4.打印路径
NSLog(@"-----字典存储路径 :%@",preferencePath);
//5.读取文件
NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:preferencePath];
NSLog(@" ----- NSDictionary :%@",dictionary);
#pragma mark ----- NSdata写入文件
//1.准备图片对象
UIImage *image = [UIImage imageNamed:@"10.png"];
//2.准备路径
NSString *homeePath = NSHomeDirectory();
homeePath = [homeePath stringByAppendingPathComponent:@"10.png"];
//3.将图片对象转化成Data////======================================
NSData *data = UIImagePNGRepresentation(image);
//4.写入文件
[data writeToFile:homeePath atomically:YES];
//5.打印路径
NSLog(@"----- NSdata:%@",homeePath);
//6.创建图像视图//===========================================
UIImageView *imgView = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];//全屏
//7.读取图像
imgView.image = [UIImage imageWithContentsOfFile:homeePath];
//8.添加图像视图到视图
[self.view addSubview:imgView];
*/
#pragma mark ------ 复杂对象写入文件
/*
//简单对象 可以通过 writeToFile 的方式写入对象,但是 复杂文件对象 没有writeToFile的方法写入文档,所以需要借助 归档 和 反归档 的方法,将复杂对象转化成简单对象,写入文档.
SingleVip *vip = [SingleVip new];
vip.name = @"法特";
vip.assets = @"数不清";
vip.car = @"兰博基尼";
vip.age = 18;
//创建路径
NSString *homPath = NSHomeDirectory();
homPath = [homPath stringByAppendingPathComponent: @"钻石王老五.txt"];
//创建数据对象,用来存放VIP对象
NSMutableData *dataaa = [NSMutableData data];
//创建归档对象,空的.//NSKeyedArchiver(存储服务器)
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:dataaa];
//基本的数据类型如NSString、NSDictionary、NSArray、NSData、NSNumber等可以用属性列表的方法持久化到.plist 文件中,但如果是一些自定义的类的话,属性列表的方法就不管用了。archiver 方法可以做到。
//对象是NSString、NSDictionary、NSArray、NSData、NSNumber等可以直接使用NSKeyedArchiver进行归档,只有遵守了NSCoding协议的对象才可以.
//NSCoding协议有2个方法:
//1.encodingWithCoder,每次归档对象时都会调用这个方法,一般在这个方法里面指定如何归档对象中的每个实例变量,可以使用 encodeobjet: forKey: 方法归档实例变量
//2.initWithCoder,每次从文件中恢复(解码)对象时,都会调用这个方法.一般在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeObject: forKey:方法解码实例变量.
//开始归档
[archiver encodeObject:vip forKey:@"vip"];
//完成归档
[archiver finishEncoding];
//homPath中写入文件
[dataaa writeToFile:homPath atomically:YES];
//打印路径
NSLog(@"======%@",homPath);
//反归档(解码)
//将文件里的data对象读取出来
NSData *dataa = [NSData dataWithContentsOfFile:homPath];//dataa里有数据
//创建反归档对象
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:dataa];
SingleVip *vipp = [unarchiver decodeObjectForKey:@"vip"];
//完成反归档
[unarchiver finishDecoding];
//打印
NSLog(@"--=---------=----%@ %ld",vipp.name,vip.age);
//归档并不是数据持久化的一种方式,而是辅助复杂对象转化成简单对象的一种方式,真正实现数据持久化的仍然是writeToFile写入文件.
//数据持久化方式:
//plist (属性列表)
//偏好设置 NSUserDefaults(单例)
//writeToFile写入文件
//SQLite 数据库
//CoreData
*/
#pragma mark ----- downLoadTask
NSURLSessionDownloadTask *task = [[NSURLSession sharedSession] downloadTaskWithURL:[NSURL URLWithString:IMG_URL] completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) { ////////NSURLSessionDownloadTask就是代表一个下载任务。
//获取data对象(因为data可以直接写入文件)
NSData *data = [NSData dataWithContentsOfURL:location];//location:位置
//准备路径
NSString *hommePath = NSHomeDirectory();//代码得到的是应用程序目录的路径,在该目录下有三个文件夹:Documents、Library、temp以及一个.app包!该目录下就是应用程序的沙盒,应用程序只能访问该目录下的文件夹!!!
hommePath = [hommePath stringByAppendingPathComponent:@"我男神得到的"];//没有后缀默认为文件夹
NSLog(@"=-=-=-=-=-%@",hommePath);
/*
自我理解,不保证正确,但亲自试验确实可行:若用 stringByAppendingString 则需要手动在名称前加 “/”符号,而stringByAppendingPathComponent则不需要,它会自动添加
******* stringByAppendingPathComponent 和 stringByAppendingString 的区别:
NSString *imagePath = [skinPath stringByAppendingString:[NSString stringWithFormat:@"/%@",imageName]];
//stringByAppendingString是在skinPath加后缀的意思
NSString *imagePath = [skinPath stringByAppendingPathComponent:imageName];
//stringByAppendingPathComponent是在skinPath后面加上“/”号连接imageName让它成为完整的路径
NSLog(@"imagePath:%@",imagePath);
打印:
2013-11-27 14:44:30.052 Willing[2757:70b] imagePath:/Users/will/Library/Application Support/iPhone Simulator/7.0.3/Applications/DA5B603D-4D07-4425-B7CC-5D49232189BE/Willing.app/tabbar_home.png
*/
// //创建 NSFileManager
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager createDirectoryAtPath:hommePath withIntermediateDirectories:YES attributes:nil error:nil];
/*
Objective-C创建目录接口createDirectoryAtPath:withIntermediateDirectories:attributes:error:中参数 attributes 的设置
在应用程序执行时,经常需要本地化保存一些重要的数据,这时就有可能需要创建一些目录。Objective-C提供了一个非常强大的创建目录的接口:
- (BOOL)createDirectoryAtPath:(NSString *)path withIntermediateDirectories:(BOOL)createIntermediates attributes:(NSDictionary *)attributes error:(NSError **)error;
很多人使用这个接口时,往往将attributes参数设置为nil,这样虽然能够创建出目录,但是在一些特殊场景下(比如iPhone的apps)所创建的目录的属性往往不是我们期望的,因而导致目录的读写失败等问题。其实通过设置attributes参数,这个接口可以完成我们的期望。
根据苹果官方文档介绍,这个参数可以设置所创建目录所属的用户和用户组,目录的访问权限和修改时间等。如果设置为nil,那么所创建目录的属性则采用系统默认设置,一般会将目录的用户设置为root,访问权限设置为0755,这样就导致其他用户向这个目录写入时失败。
attributes参数是一个字典类型。查看苹果官方文档的介绍,可以看到在NSFileManager.h头文件定义了很多常量字符串,用于作为attributes字典的键,针对于这个接口的键主要包括下面几个:
NSString * const NSFileType;
NSString * const NSFileSize;
NSString * const NSFileModificationDate;
NSString * const NSFileReferenceCount;
NSString * const NSFileDeviceIdentifier;
NSString * const NSFileOwnerAccountName;
NSString * const NSFileGroupOwnerAccountName;
NSString * const NSFilePosixPermissions;
NSString * const NSFileSystemNumber;
NSString * const NSFileSystemFileNumber;
NSString * const NSFileExtensionHidden;
NSString * const NSFileHFSCreatorCode;
NSString * const NSFileHFSTypeCode;
NSString * const NSFileImmutable;
NSString * const NSFileAppendOnly;
NSString * const NSFileCreationDate;
NSString * const NSFileOwnerAccountID;
NSString * const NSFileGroupOwnerAccountID;
NSString * const NSFileBusy;
本文不打算翻译苹果的官方文档,只把我们比较关心的几个键的意义说明如下:
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对象,表示目录的引用计数,即这个目录的硬链接数。
这样,通过合理的设计attributes字典中的不同键的值,这个接口所创建的目录的属性就会基本满足我们的需求了。
*/
/*
iphone创建文件
注意2点:
1、创建多级目录的文件时,要先判断其目录是否存在,如果不存在就创建该目录,如果没有创建该目录,文件是不能创建成功的
2、不要使用- (BOOL)createDirectoryAtPath:(NSString *)path attributes:(NSDictionary *)attributes,这个方法在模拟器中可能能成功运行,但在设备上肯定不行的,
改用- (BOOL)createDirectoryAtPath:(NSString *)path withIntermediateDirectories:(BOOL)createIntermediates attributes:(NSDictionary *)attributes error:(NSError **)error,
记得将createIntermediates设置为YES,这样就能建立//多级\\目录了。如果是一级目录,可以设置为NO。
*/
//创建文件
hommePath = [hommePath stringByAppendingString:@"/god"];
//创建目录
[fileManager createFileAtPath:hommePath contents:data attributes:nil];
NSLog(@"===============hommePath:%@",hommePath);
/*
//测试文件是否存在
[fileManager fileExistsAtPath:hommePath isDirectory:YES];
//深度遍历目录
[fileManager subpathsOfDirectoryAtPath:hommePath error:nil];
//移动/重命名文件或目录
NSString *hommmePath = NSHomeDirectory();
hommmePath = [hommmePath stringByAppendingPathComponent:@"得到的"];
[fileManager moveItemAtPath:hommePath toPath:hommmePath error:nil];
//测试文件是否存在
[fileManager fileExistsAtPath:hommmePath];
//获取文件信息
[fileManager attributesOfItemAtPath:hommmePath error:nil];
//从文件读取数据
[fileManager contentsAtPath:hommmePath];
NSLog(@"%@",hommmePath);
//比较两个文件的内容
BOOL mm = [fileManager contentsEqualAtPath:hommePath andPath:hommmePath];
*/
#pragma mark ------- NSFileManager 创建 判断是否存在 复制 移动 删除(接downLoadTask)
//创建文件夹
NSString *documentsPath1 = NSHomeDirectory();
NSString *testDirectory1 = [documentsPath1 stringByAppendingPathComponent:@"test"];
NSFileManager *fileManager1 = [NSFileManager defaultManager];
// 创建目录
BOOL res=[fileManager1 createDirectoryAtPath:testDirectory1 withIntermediateDirectories:YES attributes:nil error:nil];
if (res) {
NSLog(@"文件夹创建成功");
}else{
NSLog(@"文件夹创建失败");
}
//创建文件
NSString *testPath2 = [testDirectory1 stringByAppendingPathComponent:@"test.txt"];
BOOL res2=[fileManager1 createFileAtPath:testPath2 contents:nil attributes:nil];
if (res2) {
NSLog(@"文件创建成功: %@" ,testPath2);
}else {
NSLog(@"文件创建失败");
}
//写数据到文件:
NSString *content3=@"测试写入内容!";
BOOL res3=[content3 writeToFile:testPath2 atomically:YES encoding:NSUTF8StringEncoding error:nil];
if (res3) {
NSLog(@"文件写入成功:%@",testPath2);
}else {
NSLog(@"文件写入失败");
}
//读文件数据
// NSData *data = [NSData dataWithContentsOfFile:testPath];
// NSLog(@"文件读取成功: %@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
NSString *content4 =[NSString stringWithContentsOfFile:testPath2 encoding:NSUTF8StringEncoding error:nil];
NSLog(@"文件读取成功: %@",content4);
//文件属性
NSDictionary *fileAttributes5 = [fileManager1 attributesOfItemAtPath:testPath2 error:nil];
NSArray *keys;
id key, value;
keys = [fileAttributes5 allKeys];
NSInteger count = [keys count];
for (int i = 0; i < count; i++)
{
key = [keys objectAtIndex: i];
value = [fileAttributes5 objectForKey: key];
NSLog (@"Key: %@ for value: %@", key, value);
}
//删除文件
BOOL res6 = [fileManager1 removeItemAtPath:testPath2 error:nil];
if (res6) {
NSLog(@"文件删除成功");
}else
NSLog(@"文件删除失败");
NSLog(@"检测文件是否存在: %@",[fileManager1 isExecutableFileAtPath:testPath2]?@"YES":@"NO");
}];
[task resume];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
SingleVip.h
//
// SingleVip.h
// 沙盒机制
//
//
#import <Foundation/Foundation.h>
@interface SingleVip : NSObject<NSCoding>
@property(nonatomic, strong)NSString *name;
@property(nonatomic, strong)NSString *assets;//资产
@property(nonatomic, strong)NSString *car;
@property(nonatomic, assign)NSInteger age;
@end
SingleVip.m
//
// SingleVip.m
// 沙盒机制
//
//
#import "SingleVip.h"
#define kName @"name"
#define kAssets @"assets"
#define kCar @"car"
#define kAge @"age"
@implementation SingleVip
//编码
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:_name forKey:kName];
[aCoder encodeObject:_assets forKey:kAssets];
[aCoder encodeObject:_car forKey:kCar];
[aCoder encodeInteger:_age forKey:kAge];
}
//反编码
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder{
if (self =[super init]) {
_name = [aDecoder decodeObjectForKey:kName];
_assets = [aDecoder decodeObjectForKey:kAssets];
_car = [aDecoder decodeObjectForKey:kCar];
_age = [aDecoder decodeIntegerForKey:kAge];
}
return self;
}
@end