[iOS翻译]《iOS 7 Programming Cookbook》:iOS文件与文件夹管理(下)
三. 创建文件夹
问题:
你想创建文件夹到磁盘,存储一些文件到里面
解决方案:
使NSFileManager类的实例方法createDirectoryAtPath:withIntermediateDirectories:attributes:error:,代码如下:
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSFileManager *fileManager = [[NSFileManager alloc] init]; NSString *tempDir = NSTemporaryDirectory();
NSString *imagesDir = [tempDir stringByAppendingPathComponent:@"images"]; NSError *error = nil;
if ([fileManager createDirectoryAtPath:imagesDir
withIntermediateDirectories:YES
attributes:nil
error:&error]){
NSLog(@"Successfully created the directory."); } else {
NSLog(@"Failed to create the directory. Error = %@", error);
} self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
讨论
NSFileManager如此简洁易用,仅用几行就搞定了文件夹创建,下面是方法参数:
- createDirectoryAtPath
- 创建文件夹的路径
- withIntermediateDirectories
- BOOL类型。如果设为YES,将会自动补全最终文件夹之前的中间目录
- 例如,如果你想在tmp/data目录创建一个images文件夹,但data文件夹并不存在,怎么办?只需要把withIntermediateDirectories参数设为YES,系统就会自动创建目录tmp/data/images/
- attributes
- 通常设为nil
- error
- 接受一个指针指向NSError对象
四. 枚举文件/文件夹
问题:
你想在一个文件夹里枚举文件/文件夹列表,这个枚举动作意味着你想找到所有文件/文件夹
解决方案:
使用NSFileManager类的实例方法contentsOfDirectoryAtPath:error:。例如我们想要在bundle文件夹下枚举所有文件/文件夹,代码如下:
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSString *bundleDir = [[NSBundle mainBundle] bundlePath];
NSError *error = nil;
NSArray *bundleContents = [fileManager
contentsOfDirectoryAtPath:bundleDir
error:&error]; if ([bundleContents count] > && error == nil){
NSLog(@"Contents of the app bundle = %@", bundleContents);
}
else if ([bundleContents count] == && error == nil){
NSLog(@"Call the police! The app bundle is empty.");
}
else {
NSLog(@"An error happened = %@", error);
} self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
讨论
在一些APP里,你可能需要枚举一个文件夹的内容,让我们来看一个例子吧。
想象一下,用户从网络下载了10张图片并缓存到APP里,这时你需要存储它们,也就是说,你要手动创建tmp/images/目录。现在用户关闭后又打开了APP,在界面上,你想要在一个table view里展示下载完成列表,该如何实现?
其实很简单,需要做的就是在目录里使用NSFileManager类进行内容枚举。在解决方案部分,你已经使用了NSFileManager类的实例方法contentsOfDirectoryAtPath:error:进行枚举,然而这个方法并不能指出哪个是文件,哪个是文件夹等等。想要从文件管理里获取更多细节,调用方法contentsOfDirectoryAtURL:includingPropertiesForKeys:options:error:,参数如下:
- contentsOfDirectoryAtURL
- 想要检索的文件夹路径(NSURL类型)
- includingPropertiesForKeys
- NSArray类型,代表检索目录下个各个条目的信息
- NSURLIsDirectoryKey
- 是否是一个字典
- NSURLIsReadableKey
- 是否可读
- NSURLIsReadableKey
- NSURLCreationDateKey
- 创建日期
- NSURLCreationDateKey
- NSURLContentAccessDateKey
- 访问日期
- NSURLContentAccessDateKey
- NSURLContentModificationDateKey
- 修改日期
- NSURLContentModificationDateKey
- options
- 参数只能为0或NSDirectoryEnumerationSkipsHiddenFiles,后者在枚举时会跳过隐藏内容
- error
- 接受一个指针指向NSError对象
现在我们在XXX.app目录下进行枚举,并打印各条目的名字、是否为字典、是否可读以及创建/最后修改/最后访问的日期,代码如下;
- (NSArray *) contentsOfAppBundle{
NSFileManager *manager = [[NSFileManager alloc] init]; NSURL *bundleDir = [[NSBundle mainBundle] bundleURL]; NSArray *propertiesToGet = @[
NSURLIsDirectoryKey,
NSURLIsReadableKey,
NSURLCreationDateKey,
NSURLContentAccessDateKey,
NSURLContentModificationDateKey
]; NSError *error = nil;
NSArray *result = [manager contentsOfDirectoryAtURL:bundleDir
includingPropertiesForKeys:propertiesToGet
options:
error:&error]; if (error != nil){
NSLog(@"An error happened = %@", error);
}
return result;
}
- (NSString *) stringValueOfBoolProperty:(NSString *)paramProperty ofURL:(NSURL *)paramURL{
NSNumber *boolValue = nil;
NSError *error = nil;
[paramURL getResourceValue:&boolValue
forKey:paramProperty
error:&error]; if (error != nil){
NSLog(@"Failed to get property of URL. Error = %@", error);
}
return [boolValue isEqualToNumber:@YES] ? @"Yes" : @"No";
}
- (NSString *) isURLDirectory:(NSURL *)paramURL{
return [self stringValueOfBoolProperty:NSURLIsDirectoryKey ofURL:paramURL];
} - (NSString *) isURLReadable:(NSURL *)paramURL{
return [self stringValueOfBoolProperty:NSURLIsReadableKey ofURL:paramURL];
}
- (NSDate *) dateOfType:(NSString *)paramType inURL:(NSURL *)paramURL{
NSDate *result = nil;
NSError *error = nil;
[paramURL getResourceValue:&result
forKey:paramType
error:&error]; if (error != nil){
NSLog(@"Failed to get property of URL. Error = %@", error);
}
return result;
}
- (void) printURLPropertiesToConsole:(NSURL *)paramURL{ NSLog(@"Item name = %@", [paramURL lastPathComponent]); NSLog(@"Is a Directory? %@", [self isURLDirectory:paramURL]); NSLog(@"Is Readable? %@", [self isURLReadable:paramURL]); NSLog(@"Creation Date = %@",
[self dateOfType:NSURLCreationDateKey inURL:paramURL]); NSLog(@"Access Date = %@",
[self dateOfType:NSURLContentAccessDateKey inURL:paramURL]); NSLog(@"Modification Date = %@",
[self dateOfType:NSURLContentModificationDateKey inURL:paramURL]); NSLog(@"-----------------------------------");
}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSArray *itemsInAppBundle = [self contentsOfAppBundle];
for (NSURL *item in itemsInAppBundle){
[self printURLPropertiesToConsole:item];
} self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
输出结果类似下列信息:
Item name = Assets.car
Is a Directory? No
Is Readable? Yes
Creation Date = -- :: +
Access Date = -- :: +
Modification Date = -- :: +
-----------------------------------
Item name = en.lproj
Is a Directory? Yes
Is Readable? Yes
Creation Date = -- :: +
Access Date = -- :: +
Modification Date = -- :: +
-----------------------------------
Item name = Enumerating Files and Folders
Is a Directory? No
Is Readable? Yes
Creation Date = -- :: +
Access Date = -- :: +
Modification Date = -- :: +
-----------------------------------
我们来看看这段代码的一些方法:
- contentsOfAppBundle
- 这个方法搜索.app文件夹的所有条目(文件、文件夹等等),并返回一个数组
- 数组里的所有条目都为NSURL类型,并包含了创建/最后修改日期以及其他之前提到的属性
- stringValueOfBoolProperty:ofURL:
- 返回与BOOL类型相当的NSString(YES或NO),用来判断URL的信息
- isURLDirectory:
- 是否是字典
- isURLReadable:
- 是否可读
- dateOfType:inURL:
- 日期类型
现在,你已经知道如何在一个文件夹里遍历所有条目,甚至学会了检索各个条目的不同属性。
五. 删除文件/文件夹
问题:
你想删除一些文件或文件夹
解决方案:
使用NSFileManager类的实例方法removeItemAtPath:error:(接收string)或者removeItemAtURL:error:(接收URL)
讨论
删除文件/文件夹应该是使用file manager时最简单的操作了。现在,让我们来创建5个text文件到tmp/text目录,然后进行删除操作,代码如下;
/* Creates a folder at a given path */
- (void) createFolder:(NSString *)paramPath{
NSError *error = nil;
if ([self.fileManager createDirectoryAtPath:paramPath
withIntermediateDirectories:YES
attributes:nil
error:&error] == NO){
NSLog(@"Failed to create folder %@. Error = %@",
paramPath,
error);
}
}
/* Creates 5 .txt files in the given folder, named 1.txt, 2.txt, etc */
- (void) createFilesInFolder:(NSString *)paramPath{
/* Create 10 files */
for (NSUInteger counter = ; counter < ; counter++){
NSString *fileName = [NSString stringWithFormat:@"%lu.txt", (unsigned long)counter+];
NSString *path = [paramPath stringByAppendingPathComponent:fileName];
NSString *fileContents = [NSString stringWithFormat:@"Some text"];
NSError *error = nil;
if ([fileContents writeToFile:path
atomically:YES
encoding:NSUTF8StringEncoding
error:&error] == NO){
NSLog(@"Failed to save file to %@. Error = %@", path, error);
}
}
}
/* Enumerates all files/folders at a given path */
- (void) enumerateFilesInFolder:(NSString *)paramPath{
NSError *error = nil;
NSArray *contents = [self.fileManager contentsOfDirectoryAtPath:paramPath
error:&error]; if ([contents count] > && error == nil){
NSLog(@"Contents of path %@ = \n%@", paramPath, contents);
}
else if ([contents count] == && error == nil){
NSLog(@"Contents of path %@ is empty!", paramPath);
}
else {
NSLog(@"Failed to enumerate path %@. Error = %@", paramPath, error);
}
}
/* Deletes all files/folders in a given path */
- (void) deleteFilesInFolder:(NSString *)paramPath{
NSError *error = nil;
NSArray *contents = [self.fileManager contentsOfDirectoryAtPath:paramPath error:&error]; if (error == nil){
error = nil;
for (NSString *fileName in contents){
/* We have the file name, to delete it,
we have to have the full path */
NSString *filePath = [paramPath
stringByAppendingPathComponent:fileName];
if ([self.fileManager removeItemAtPath:filePath error:&error] == NO){
NSLog(@"Failed to remove item at path %@. Error = %@", fileName, error);
}
}
} else {
NSLog(@"Failed to enumerate path %@. Error = %@", paramPath, error);
}
}
/* Deletes a folder with a given path */
- (void) deleteFolder:(NSString *)paramPath{
NSError *error = nil;
if ([self.fileManager removeItemAtPath:paramPath error:&error] == NO){
NSLog(@"Failed to remove path %@. Error = %@", paramPath, error);
}
}
#import "AppDelegate.h" @interface AppDelegate ()
@property (nonatomic, strong) NSFileManager *fileManager;
@end @implementation AppDelegate <# Rest of your app delegate code goes here #>
示例代码结合了这一章的很多知识,下面来看一看这些方法的步骤:
- 1.创建了tmp/txt目录。我们知道tmp文件夹在APP安装时自动创建,但txt文件夹则需要手动创建
- 2.在tmp/txt目录创建5个text文件
- 3.在tmp/txt目录枚举所有文件
- 4.在tmp/txt目录删除文件
- 5.再次在tmp/txt目录枚举剩下的文件
- 6.在tmp/txt目录删除文件夹
现在你不光学会了如何创建文件/文件夹,还学会了如何在不需要时删除它们。
六. 存储对象到文件
问题:
你添加了一些新类到项目里,这时你想把这些对象作为文件存储到磁盘里,当需要时能随时读取
解决方案:
确保你的类遵从NSCoding协议,并且实现协议必要方法
讨论
iOS SDK里有两个非常方便的类来实现这一目标,在编程世界里称为marshalling,它们是:
- NSKeyedArchiver
- 归档
- NSKeyedUnarchiver
- 解档
为了实现归档/解档工作,需要遵从NSCoding协议,现在来创建一个简单的Person类,头文件如下:
#import <Foundation/Foundation.h> @interface Person : NSObject <NSCoding> @property (nonatomic, copy) NSString *firstName;
@property (nonatomic, copy) NSString *lastName; @end
协议要求必须实现两个方法:
- - (void)encodeWithCoder:(NSCoder *)aCoder
- 给你一个coder,使用方法类似字典
- - (instancetype)initWithCoder:(NSCoder *)aDecoder
- 当你试图使用NSKeyedUnarchiver进行解档时,这个方法会被调用
现在来来到实现文件,代码如下:
#import "Person.h" NSString *const kFirstNameKey = @"FirstNameKey";
NSString *const kLastNameKey = @"LastNameKey"; @implementation Person - (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.firstName forKey:kFirstNameKey];
[aCoder encodeObject:self.lastName forKey:kLastNameKey];
} - (instancetype)initWithCoder:(NSCoder *)aDecoder{ self = [super init];
if (self != nil){
_firstName = [aDecoder decodeObjectForKey:kFirstNameKey];
_lastName = [aDecoder decodeObjectForKey:kLastNameKey];
}
return self;
} @end
接着在AppDelegate实现如下方法:
#import "AppDelegate.h"
#import "Person.h" @implementation AppDelegate - (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
/* Define the name and the last name we are going to set in the object */
NSString *const kFirstName = @"Steven";
NSString *const kLastName = @"Jobs"; /* Determine where we want to archive the object */
NSString *filePath = [NSTemporaryDirectory()
stringByAppendingPathComponent:@"steveJobs.txt"]; /* Instantiate the object */
Person *steveJobs = [[Person alloc] init];
steveJobs.firstName = kFirstName;
steveJobs.lastName = kLastName; /* Archive the object to the file */
[NSKeyedArchiver archiveRootObject:steveJobs toFile:filePath]; /* Now unarchive the same class into another object */
Person *cloneOfSteveJobs =
[NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; /* Check if the unarchived object has the same first name and last name
as the previously-archived object */
if ([cloneOfSteveJobs.firstName isEqualToString:kFirstName]
&& [cloneOfSteveJobs.lastName isEqualToString:kLastName]){
NSLog(@"Unarchiving worked");
} else {
NSLog(@"Could not read the same values back. Oh no!");
} /* We no longer need the temp file, delete it */
NSFileManager *fileManager = [[NSFileManager alloc] init];
[fileManager removeItemAtPath:filePath error:nil];
self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
可见,归档只需要使用NSKeyedArchiver类的类方法archiveRootObject:toFile就能搞定,那如何解档呢?使用另外一个类方法unarchiveObjectWithFile:就行。
[iOS翻译]《iOS 7 Programming Cookbook》:iOS文件与文件夹管理(下)的更多相关文章
- [iOS翻译]《iOS 7 Programming Cookbook》:iOS文件与文件夹管理(上)
简介: iOS基于OS X,而OSX本身基于Unix操作系统.在iOS里面,操作系统的完全路径结构是不可见的,因为每个APP的数据都存储自身的沙盒里面.沙盒环境实际上听起来像这样:一个只允许当前APP ...
- [book] iOS 8 Swift Programming Cookbook
iOS 8 Swift Programming Cookbook 资源地址 http://pan.baidu.com/s/1c0hn1Gc 书籍介绍 源码截图 书籍截图
- [IOS/翻译]Core Services Layer
本文是本人自己辛苦翻译的,请转载的朋友注明,翻译于Z.MJun的CSDN的博客 http://blog.csdn.net/Zheng_Paul,感谢. 翻译于2015年10月4日 Core Servi ...
- iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载+使用输出流代替文件句柄
前言:本篇讲解,在前篇iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载的基础上,使用输出流代替文件句柄实现大文件断点续传. 在实际开发中,输入输出流用的比较少,但 ...
- IOS证书/私钥/代码签名/描述文件
1. 相关资源 (1) 钥匙串程序(常用工具->钥匙串),用于创建证书请求.安装证书.导出私钥等 (2) IOS开发中心:https://developer.apple.com/de ...
- iOS开发——Swift篇&文件,文件夹操作
文件,文件夹操作 ios开发经常会遇到读文件,写文件等,对文件和文件夹的操作,这时就可以使用NSFileManager,NSFileHandle等类来实现. 下面总结了各种常用的操作: 1,遍 ...
- iOS Dev (20) 用 AVAudioPlayer 播放一个本地音频文件
iOS Dev (20) 用 AVAudioPlayer 播放一个本地音频文件 作者:CSDN 大锐哥 博客:http://blog.csdn.net/prevention 步骤 第一步:在 Proj ...
- iOS Dev (21) 用 AVPlayer 播放一个本地音频文件
iOS Dev (21) 用 AVPlayer 播放一个本地音频文件 作者:CSDN 大锐哥 博客:http://blog.csdn.net/prevention 前言 这篇文章与上一篇极其相似,要注 ...
- iOS 11开发教程(六)iOS11Main.storyboard文件编辑界面
iOS 11开发教程(六)iOS11Main.storyboard文件编辑界面 在1.2.2小节中提到过编辑界面(Interface builder),编辑界面是用来设计用户界面的,单击打开Main. ...
随机推荐
- 忙碌的Nova君 (活动安排问题、贪心算法)
题目描述 理论上,Nova君是个大闲人,但每天还是有一大堆事要干,大作业啦,创新杯啦,游戏啦,出题坑人啦,balabala......然而精力有限,Nova君同一时间只能做一件事,并不能一心二用.假设 ...
- 后台API服务的设计考虑
我在<写在最前>里说过,后台API的文档至关重要.不过,文档只是外在表现形式,设计才是真正的灵魂.我在这篇博文主要介绍的就是我在后台开发过程中,设计API时的考虑.我只说他是考虑,因为很多 ...
- 采用 PAT工具及CSP语言,对一个问题进行自动机 建模
pat是新加坡国立开发的工具,需要的去官网下http://www.comp.nus.edu.sg/~pat/ ,学了一天,是个不错的自动机验证工具,感觉还不错啊. 验证一个数是否为斐波那契数且为质数 ...
- linux下使用正确的用户名密码,本地无法连接mysql
问题现象: Linux系统为CentOS 7.0 64位,通过IP远程mysql时,可以正常访问,确定账号密码没有问题.但是本地连接mysql时,提示ERROR 1045 (28000): Acces ...
- keepalived+LVS搭建高可用负载均衡系统
相关架构设置: 1)vip : 192.168.137.6 2)DS master ip : 192.168.137.8 3)DS backup ip : 192.168.137.9 4)RS 1 i ...
- 算法(二)之遗传算法(SGA)
算法(二)之遗传算法(SGA) 遗传算法(Genetic Algorithm)又叫基因进化算法或进化算法,是模拟达尔文的遗传选择和自然淘汰的生物进化过程的计算模型,属于启发式搜索算法一种. 下面通过下 ...
- Oracle-创建服务器参数文件
允许使用传统的init.ora或SPFILE作为配置文件.但是建议所有数据库创建和使用一个SPFILE.可以从init.ora创建SPFILE SQL> CREATE spfile FROM p ...
- mysql连接其他表删除某个表的数据
delete a from TableA a left join TableB b on a.XX = b.YY left join TableC c on c.ZZ = a.XX where 条件
- Ubuntu,QT5连接MySQL
用QT连接MySQL需要共享库 libqsqlmysql.so的驱动,路径在plugin/sqldrivers目录下,乍看已经可用了,其实不然. 用ldd命令分析一下,libmysqlclient_r ...
- 仅IE6中链接A的href为javascript协议时不能在当前页面跳转
切页面时有时用链接A来替代按钮,这样做有几个好处 鼠标放上时默认有手状效果(不用添加cursor:pointer) 可以添加低版本IE都支持的伪类 如果点击时页面要整体刷新,即跳转,这时IE6则不尽人 ...