转载:http://www.uml.org.cn/mobiledev/201209211.asp#1尊重原创
目录:
IOS学习之IOS沙盒(sandbox)机制和文件操作(一)
IOS学习之IOS沙盒(sandbox)机制和文件操作(二)
IOS学习之IOS沙盒(sandbox)机制和文件操作之NSFileManager(三)
IOS学习之IOS沙盒(sandbox)机制和文件操作(一)
1、IOS沙盒机制
IOS应用程序只能在为该改程序创建的文件系统中读取文件,不可以去其它地方访问,此区域被成为沙盒,所以所有的非代码文件都要保存在此,例如图像,图标,声音,映像,属性列表,文本文件等。
1.1、每个应用程序都有自己的存储空间
1.2、应用程序不能翻过自己的围墙去访问别的存储空间的内容
1.3、应用程序请求的数据都要通过权限检测,假如不符合条件的话,不会被放行。
通过这张图只能从表层上理解sandbox是一种安全体系,应用程序的所有操作都要通过这个体系来执行,其中核心内容是:sandbox对应用程序执行各种操作的权限限制。
2、打开模拟器沙盒目录
下面看看模拟器的沙盒文件夹在mac电脑上的什么位置。
文件都在个人用户名文件夹下的一个隐藏文件夹里,中文叫资源库,他的目录其实是Library。
2.1 方法1、可以设置显示隐藏文件,然后在Finder下直接打开。设置查看隐藏文件的方法如下:打开终端,输入命名
显示Mac隐藏文件的命令:defaults write com.apple.finder AppleShowAllFiles -bool true
隐藏Mac隐藏文件的命令:defaults write com.apple.finder AppleShowAllFiles -bool false
输完单击Enter键,退出终端,
重新启动Finder就可以了重启Finder:鼠标单击窗口左上角的苹果标志-->强制退出-->Finder-->
现在能看到资源库文件夹了。
打开资源库后找到/Application Support/iPhone Simulator/文件夹。这里面就是模拟器的各个程序的沙盒目录了。
2.2 方法2、这种方法更方便,在Finder上点->前往->前往文件夹,输入/Users/username/Library/Application Support/iPhone Simulator/ 前往。
username这里写你的用户名。
3、目录结构
默认情况下,每个沙盒含有3个文件夹:Documents, Library 和 tmp。因为应用的沙盒机制,应用只能在几个目录下读写文件
Documents:苹果建议将程序中建立的或在程序中浏览到的文件数据保存在该目录下,iTunes备份和恢复的时候会包括此目录
Library:存储程序的默认设置或其它状态信息;
Library/Caches:存放缓存文件,iTunes不会备份此目录,此目录下文件不会在应用退出删除
tmp:提供一个即时创建临时文件的地方。
iTunes在与iPhone同步时,备份所有的Documents和Library文件。
iPhone在重启时,会丢弃所有的tmp文件。
我们创建一个IosSandbox的项目来展开沙盒和文件读写等操作的练习。
创建后找到模拟器上对应的目录,
这是目录全展开了。
这是上面提到的三个目录 :Documents、Library、 tmp
下篇介绍目录路径获取和文件操作
IOS学习之IOS沙盒(sandbox)机制和文件操作(二)
我们看看如何获取应用程序沙盒目录。包括真机的沙盒的目录。
1、获取程序的Home目录
NSString *homeDirectory = NSHomeDirectory(); NSLog(@"path:%@", homeDirectory); |
打印结果:
2012-06-17 14:00:06.098 IosSandbox[3536:f803] /Users/rongfzh/Library/Application Support/iPhone Simulator/5.1/ Applications/3B8EC78A-5EEE-4C2F-B0CB-4C3F02B996D2 |
那在真机上的目录有是怎么样的呢?我们看看
2012-06-17 14:25:47.059 IosSandbox[4281:f803] /var/mobile/Applications/3B8EC78A-5EEE-4C2F-B0CB-4C3F02B996D2
可见,真机上的目录是/var/mobile/Applications/这个目录下的,和模拟器不一样。这个是Home目录,其他的子目录和模拟器一样。
2、获取document目录
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *path = [paths objectAtIndex:0]; NSLog(@"path:%@", path); |
打印结果
2012-06-17 14:00:06.099 IosSandbox[3536:f803] path:/Users/rongfzh/Library/Application Support/iPhone Simulator/5.1 /Applications/3B8EC78A-5EEE-4C2F-B0CB-4C3F02B996D2/Documents |
3、获取Cache目录
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *path = [paths objectAtIndex:0]; NSLog(@"%@", path); |
打印结果:
2012-06-17 14:03:50.431 IosSandbox[3628:f803] /Users/rongfzh/Library/Application Support/iPhone Simulator/5.1 /Applications/3B8EC78A-5EEE-4C2F-B0CB-4C3F02B996D2/Library/Caches |
4、获取Library目录
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); NSString *path = [paths objectAtIndex:0]; NSLog(@"%@", path); |
打印结果:
2012-06-17 14:07:17.544 IosSandbox[3733:f803] /Users/rongfzh/Library/Application Support/iPhone Simulator/5.1 /Applications/3B8EC78A-5EEE-4C2F-B0CB-4C3F02B996D2/Library |
5、获取Tmp目录
NSString *tmpDir = NSTemporaryDirectory(); NSLog(@"%@", tmpDir); |
打印结果:
2012-06-17 14:08:07.824 IosSandbox[3782:f803] /var/folders/g7/246bh79130zblw0yjjtc55cw0000gn/T/ |
6、写入文件
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *docDir = [paths objectAtIndex:0]; if (!docDir) { NSLog(@"Documents 目录未找到"); } NSArray *array = [[NSArray alloc] initWithObjects:@"内容",@"content",nil]; NSString *filePath = [docDir stringByAppendingPathComponent:@"testFile.txt"]; [array writeToFile:filePath atomically:YES]; |
注:我们在真机上也运行一下,把文件写入,下一步从真机上把内容读取出来。
写入输入 array ,里面是两个字符串,一会我们读出来打印。
写入我们在程序沙盒目录下看到文件 testFile.txt
打开文件看到的内容是这样的,是个xml格式的plist文件,数据格式保存了内容。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <array> <string>内容</string> <string>content</string> </array> </plist> |
7、读取文件
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *docDir = [paths objectAtIndex:0]; NSString *filePath = [docDir stringByAppendingPathComponent:@"testFile.txt"]; NSArray *array = [[NSArray alloc]initWithContentsOfFile:filePath]; NSLog(@"%@", array); |
打印结果:
把上面的文件解析后,把内容打印出来了。
2012-06-17 14:14:46.249 IosSandbox[3918:f803] ( "\U5185\U5bb9", content ) |
真机上读取并打印文件路径:
2012-06-17 14:25:47.059 IosSandbox[4281:f803] /var/mobile/Applications/3B8EC78A-5EEE-4C2F-B0CB-4C3F02B996D2/Documents/testFile.txt
(
"\U5185\U5bb9",
content
)
真机上也能写入和打印。
IOS学习之IOS沙盒(sandbox)机制和文件操作之NSFileManager(三)
我们看看NSFileManager如何使用。包括创建文件,目录,删除,遍历目录等。
1、在Documents里创建目录
创建一个叫test的目录,先找到Documents的目录,
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSLog(@"documentsDirectory%@",documentsDirectory); NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *testDirectory = [documentsDirectory stringByAppendingPathComponent:@"test"]; // 创建目录 [fileManager createDirectoryAtPath:testDirectory withIntermediateDirectories:YES attributes:nil error:nil]; |
启动程序,这时候目录就创建了:
2、在test目录下创建文件
创建文件怎么办呢?接着上面的代码 testPath 要用stringByAppendingPathComponent拼接上你要生成的文件名,比如test00.txt。这样才能在test下写入文件。
testDirectory是上面代码生成的路径哦,不要忘了。我往test文件夹里写入三个文件,test00.txt ,test22.txt,text.33.txt。内容都是写入内容,write String。
实现代码如下:
NSString *testPath = [testDirectory stringByAppendingPathComponent:@"test00.txt"]; NSString *testPath2 = [testDirectory stringByAppendingPathComponent:@"test22.txt"]; NSString *testPath3 = [testDirectory stringByAppendingPathComponent:@"test33.txt"]; NSString *string = @"写入内容,write String"; [fileManager createFileAtPath:testPath contents:[string dataUsingEncoding:NSUTF8StringEncoding] attributes:nil]; [fileManager createFileAtPath:testPath2 contents:[string dataUsingEncoding:NSUTF8StringEncoding] attributes:nil]; [fileManager createFileAtPath:testPath3 contents:[string dataUsingEncoding:NSUTF8StringEncoding] attributes:nil]; |
看下面的图,三个文件都出来了,内容也对。
在Documents目录下创建就更简单了,不用加test就ok了
3、获取目录列里所有文件名
两种方法获取:subpathsOfDirectoryAtPath 和 subpathsAtPath
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSLog(@"documentsDirectory%@",documentsDirectory); NSFileManager *fileManage = [NSFileManager defaultManager]; NSString *myDirectory = [documentsDirectory stringByAppendingPathComponent:@"test"]; NSArray *file = [fileManage subpathsOfDirectoryAtPath: myDirectory error:nil]; NSLog(@"%@",file); NSArray *files = [fileManage subpathsAtPath: myDirectory ]; NSLog(@"%@",files); |
获取上面刚才test文件夹里的文件名
打印结果
2012-06-17 23:23:19.684 IosSandbox[947:f803] fileList:( ".DS_Store", "test00.txt", "test22.txt", "test33.txt" ) 2012-06-17 23:23:19.686 IosSandbox[947:f803] fileLit( ".DS_Store", "test00.txt", "test22.txt", "test33.txt" ) |
两个方法都可以,隐藏的文件也打印出来了。
4、fileManager使用操作当前目录
//创建文件管理器 NSFileManager *fileManager = [NSFileManager defaultManager]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; //更改到待操作的目录下 [fileManager changeCurrentDirectoryPath:[documentsDirectory stringByExpandingTildeInPath]]; //创建文件fileName文件名称,contents文件的内容,如果开始没有内容可以设置为nil,attributes文件的属性,初始为nil NSString * fileName = @"testFileNSFileManager.txt"; NSArray *array = [[NSArray alloc] initWithObjects:@"hello world",@"hello world1", @"hello world2",nil]; [fileManager createFileAtPath:fileName contents:array attributes:nil]; |
这样就创建了testFileNSFileManager.txt并把三个hello world写入文件了
changeCurrentDirectoryPath目录更改到当前操作目录时,做文件读写就很方便了,不用加上全路径
5、删除文件
接上面的代码,remove就ok了。
[fileManager removeItemAtPath:fileName error:nil]; |
6、混合数据的读写
用NSMutableData创建混合数据,然后写到文件里。并按数据的类型把数据读出来
6.1写入数据:
NSString * fileName = @"testFileNSFileManager.txt"; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; //获取文件路径 NSString *path = [documentsDirectory stringByAppendingPathComponent:fileName]; //待写入的数据 NSString *temp = @"nihao 世界"; int dataInt = 1234; float dataFloat = 3.14f; //创建数据缓冲 NSMutableData *writer = [[NSMutableData alloc] init]; //将字符串添加到缓冲中 [writer appendData:[temp dataUsingEncoding:NSUTF8StringEncoding]]; //将其他数据添加到缓冲中 [writer appendBytes:&dataInt length:sizeof(dataInt)]; [writer appendBytes:&dataFloat length:sizeof(dataFloat)]; //将缓冲的数据写入到文件中 [writer writeToFile:path atomically:YES]; |
我们看看数据怎么样了:
我们看到后面的是乱码,那是中文被转成了NSData后,还有int float的二进制
6.2读取刚才写入的数据:
//读取数据: int intData; float floatData = 0.0; NSString *stringData; NSData *reader = [NSData dataWithContentsOfFile:path]; stringData = [[NSString alloc] initWithData:[reader subdataWithRange:NSMakeRange(0, [temp length])] encoding:NSUTF8StringEncoding]; [reader getBytes:&intData range:NSMakeRange([temp length], sizeof(intData))]; [reader getBytes:&floatData range:NSMakeRange([temp length] + sizeof(intData), sizeof(floatData))]; NSLog(@"stringData:%@ intData:%d floatData:%f", stringData, intData, floatData); |
打印出来的结果:
2012-06-17 23:51:14.723 IosSandbox[1285:f803] stringData:nihao hello! intData:1234332 floatData:3.140000
这里把写入的汉字改成了 hello。因为[temp length]算长度是,把中文算成一位了,出来的结果有误。
NSFileHandle(文件句柄)
//文件句柄,可以当做就是文件本身,对句柄进行操作,相当于是对文件本身进行操作 //读---将数据从磁盘转移到内存 //写---将数据从内存转移到磁盘 1.+ (id)fileHandleForReadingAtPath:(NSString *)path; 读取制定路径下的内容,返回值为一个句柄 //创建读取文件的句柄 //注意:如果失败那么句柄为空 NSFileHandle *readHandle = [NSFileHandle fileHandleForReadingAtPath:PATH]; //NSLog(@"%p",readHandle); //读取指定长度的文件内容 //- (NSData *)readDataOfLength:(NSUInteger)length; 2. NSData *data = [readHandle readDataOfLength:3]; 把句柄设为3,返回值为一个二进制的数据流 NSLog(@"%@",data); 3. 把二进制的数据流转换成字符串输出 NSString *fileContents = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@",fileContents); 4.读取文件直到最后 data = [readHandle readDataToEndOfFile]; 把句柄设成末尾返回的时整个文件内容的数据流 fileContents = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@",fileContents); //字符串直接读取文件,只能把文件完整读取 5. NSString *str = [NSString stringWithContentsOfFile:PATH encoding:NSUTF8StringEncoding error:nil]; NSLog(@"%@",str); 读取文件的内容在制定的路径下 6.设置文件句柄为某一个值 [readHandle seekToFileOffset:3]; 把句柄设成3. data = [readHandle readDataToEndOfFile]; fileContents = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@",fileContents); 读取三个字节的内容 7.NSFileHandle *writeHandle = [NSFileHandle fileHandleForWritingAtPath:PATH]; 创建一个用于写文件的句柄 8.NSData *data = [@"ZZZ" dataUsingEncoding:NSUTF8StringEncoding]; 把字符串转换成二进制的数据流, //往文件里面写东西,会一个字节一个字节覆盖 //[writeHandle writeData:data]; //前面使用的句柄会将值保留下来,下一次接着用 //[writeHandle writeData:data]; NSLog(@"-----"); //- (unsigned long long)seekToEndOfFile; //直接把句柄定位到文件的最末尾 //unsigned long long index = [writeHandle seekToEndOfFile]; //NSLog(@"%lld",index); [writeHandle writeData:data]; //截断文件到指定大小 [writeHandle truncateFileAtOffset:3]; //NSString *str = @"ZZZ"; //字符串直接写入文件,会把以前的内容覆盖掉 //[str writeToFile:PATH atomically:YES encoding:NSUTF8StringEncoding error:nil]; //把内容同步到磁盘 9.写完要保存.[writeHandle synchronizeFile];
文件拷贝举例
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { NSFileManager *manager = [NSFileManager defaultManager]; NSString *path1 = @"/users/qianfeng/desktop/海阔天空.txt"; NSString *path2 = @"/users/qianfeng/desktop/img/海阔天空.txt"; BOOL isdir = NO; BOOL rec = [manager fileExistsAtPath:path2 isDirectory:&isdir]; if(!rec) { [manager createFileAtPath:path2 contents:nil attributes:nil]; NSFileHandle *read = [NSFileHandle fileHandleForReadingAtPath:path1]; NSFileHandle *write = [NSFileHandle fileHandleForWritingAtPath:path2]; NSDictionary *dic = [manager attributesOfItemAtPath:path1 error:nil]; NSNumber *length = [dic objectForKey:@"NSFileSize"]; NSLog(@"%@",length); int l = [length intValue]; while(l >0) { if(l < 100) { NSData *data = [read readDataToEndOfFile]; [write writeData:data]; l = 0; } else { NSData *data = [read readDataOfLength:100]; [write writeData:data]; l-=100; } } [write synchronizeFile]; } else { if(isdir) { NSLog(@"这是一个目录"); } else { NSLog(@"文件已经存在"); } return 0; } } return 0; }
int main() { @autoreleasepool { NSError *__autoreleasing *err=nil; NSFileManager *manager=[NSFileManager defaultManager]; NSArray *contens=[manager subpathsOfDirectoryAtPath:PATH error:&err]; NSLog(@"%@",err); for (id obj in contens) { if ([obj rangeOfString:@"."].location) { NSLog(@"%@",obj); NSArray *arr=[obj componentsSeparatedByString:@"."]; NSArray *arr1=[obj componentsSeparatedByString:@"/"]; NSString *str=[arr objectAtIndex:[arr count]-1]; NSString *str1=[arr1 objectAtIndex:[arr1 count]-1]; [manager createDirectoryAtPath:[NSString stringWithFormat:@"%@/%@",PATH,str] withIntermediateDirectories:NO attributes:nil error:nil]; [manager copyItemAtPath:[NSString stringWithFormat:@"%@/%@",PATH,str1] toPath:[NSString stringWithFormat:@"%@/%@",PATH,str] error:nil]; } } } }
所有图片都移动到新的文件夹
int main() { @autoreleasepool { NSError *__autoreleasing *err=nil; NSFileManager *manager=[NSFileManager defaultManager]; NSArray *contens=[manager subpathsOfDirectoryAtPath:PATH error:&err]; NSLog(@"%@",err); for (id obj in contens) { if ([obj rangeOfString:@"."].location) { NSLog(@"%@",obj); NSArray *arr=[obj componentsSeparatedByString:@"."]; NSArray *arr1=[obj componentsSeparatedByString:@"/"]; NSString *str=[arr objectAtIndex:[arr count]-1]; NSString *str1=[arr1 objectAtIndex:[arr1 count]-1]; [manager createDirectoryAtPath:[NSString stringWithFormat:@"%@/%@",PATH,str] withIntermediateDirectories:NO attributes:nil error:nil]; [manager copyItemAtPath:[NSString stringWithFormat:@"%@/%@",PATH,str1] toPath:[NSString stringWithFormat:@"%@/%@",PATH,str] error:nil]; } } } }
文件内容读取和json解析
#import <Foundation/Foundation.h> //文件内容的操作 //NSFileHandle #define PATH @"/users/chancelee/desktop/test.txt" #if 0 int main(int argc, const char * argv[]) { @autoreleasepool { //文件句柄,可以当做就是文件本身,对句柄进行操作,相当于是对文件本身进行操作 //读---将数据从磁盘转移到内存 //写---将数据从内存转移到磁盘 //+ (id)fileHandleWithNullDevice; //+ (id)fileHandleForReadingAtPath:(NSString *)path; //创建读取文件的句柄 //注意:如果失败那么句柄为空 NSFileHandle *readHandle = [NSFileHandle fileHandleForReadingAtPath:PATH]; //NSLog(@"%p",readHandle); //读取指定长度的文件内容 //- (NSData *)readDataOfLength:(NSUInteger)length; NSData *data = [readHandle readDataOfLength:3]; NSLog(@"%@",data); NSString *fileContents = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@",fileContents); //读取文件直到最后 data = [readHandle readDataToEndOfFile]; fileContents = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@",fileContents); //字符串直接读取文件,只能把文件完整读取 NSString *str = [NSString stringWithContentsOfFile:PATH encoding:NSUTF8StringEncoding error:nil]; NSLog(@"%@",str); //设置文件句柄为某一个值 [readHandle seekToFileOffset:3]; data = [readHandle readDataToEndOfFile]; fileContents = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@",fileContents); } return 0; } #endif int main() { NSFileHandle *writeHandle = [NSFileHandle fileHandleForWritingAtPath:PATH]; NSData *data = [@"ZZZ" dataUsingEncoding:NSUTF8StringEncoding]; //往文件里面写东西,会一个字节一个字节覆盖 //[writeHandle writeData:data]; //前面使用的句柄会将值保留下来,下一次接着用 //[writeHandle writeData:data]; NSLog(@"-----"); //- (unsigned long long)seekToEndOfFile; //直接把句柄定位到文件的最末尾 //unsigned long long index = [writeHandle seekToEndOfFile]; //NSLog(@"%lld",index); [writeHandle writeData:data]; //截断文件到指定大小 [writeHandle truncateFileAtOffset:3]; //NSString *str = @"ZZZ"; //字符串直接写入文件,会把以前的内容覆盖掉 //[str writeToFile:PATH atomically:YES encoding:NSUTF8StringEncoding error:nil]; //把内容同步到磁盘 [writeHandle synchronizeFile]; } //json //json的数据格式: //[]数组 //{}字典 //"":""键值对 //多个键值对之间以,隔开 //不同于xml,轻量级,减少冗余的数据,缩短下载的时间,节省流量 #define PATH @"/users/chancelee/desktop/test.json" int main(int argc, const char * argv[]) { @autoreleasepool { //可以直接用字符串将json文件读取出来 NSString *str = [NSString stringWithContentsOfFile:PATH encoding:NSUTF8StringEncoding error:nil]; NSLog(@"%@",str); //NSJSONSerialization NSData *data = [NSData dataWithContentsOfFile:PATH]; NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); /** * typedef NS_OPTIONS(NSUInteger, NSJSONReadingOptions) { NSJSONReadingMutableContainers = (1UL << 0), 指定成可变的数组或者字典 NSJSONReadingMutableLeaves = (1UL << 1), 指定成可变字符串 NSJSONReadingAllowFragments = (1UL << 2) 不指定解析的类型 }; */ id obj = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil]; NSLog(@"%@",obj); NSLog(@"%@",[obj class]); } return 0; }