三. 创建文件夹

问题:

你想创建文件夹到磁盘,存储一些文件到里面

解决方案:

使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  

      • 是否可读    
    • NSURLCreationDateKey  

      • 创建日期    
    • NSURLContentAccessDateKey  

      • 访问日期    
    • 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文件与文件夹管理(下)的更多相关文章

  1. [iOS翻译]《iOS 7 Programming Cookbook》:iOS文件与文件夹管理(上)

    简介: iOS基于OS X,而OSX本身基于Unix操作系统.在iOS里面,操作系统的完全路径结构是不可见的,因为每个APP的数据都存储自身的沙盒里面.沙盒环境实际上听起来像这样:一个只允许当前APP ...

  2. [book] iOS 8 Swift Programming Cookbook

    iOS 8 Swift Programming Cookbook 资源地址 http://pan.baidu.com/s/1c0hn1Gc 书籍介绍 源码截图 书籍截图

  3. [IOS/翻译]Core Services Layer

    本文是本人自己辛苦翻译的,请转载的朋友注明,翻译于Z.MJun的CSDN的博客 http://blog.csdn.net/Zheng_Paul,感谢. 翻译于2015年10月4日 Core Servi ...

  4. iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载+使用输出流代替文件句柄

    前言:本篇讲解,在前篇iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载的基础上,使用输出流代替文件句柄实现大文件断点续传.    在实际开发中,输入输出流用的比较少,但 ...

  5. IOS证书/私钥/代码签名/描述文件

    1.   相关资源 (1)   钥匙串程序(常用工具->钥匙串),用于创建证书请求.安装证书.导出私钥等 (2)   IOS开发中心:https://developer.apple.com/de ...

  6. iOS开发——Swift篇&文件,文件夹操作

    文件,文件夹操作   ios开发经常会遇到读文件,写文件等,对文件和文件夹的操作,这时就可以使用NSFileManager,NSFileHandle等类来实现. 下面总结了各种常用的操作:   1,遍 ...

  7. iOS Dev (20) 用 AVAudioPlayer 播放一个本地音频文件

    iOS Dev (20) 用 AVAudioPlayer 播放一个本地音频文件 作者:CSDN 大锐哥 博客:http://blog.csdn.net/prevention 步骤 第一步:在 Proj ...

  8. iOS Dev (21) 用 AVPlayer 播放一个本地音频文件

    iOS Dev (21) 用 AVPlayer 播放一个本地音频文件 作者:CSDN 大锐哥 博客:http://blog.csdn.net/prevention 前言 这篇文章与上一篇极其相似,要注 ...

  9. iOS 11开发教程(六)iOS11Main.storyboard文件编辑界面

    iOS 11开发教程(六)iOS11Main.storyboard文件编辑界面 在1.2.2小节中提到过编辑界面(Interface builder),编辑界面是用来设计用户界面的,单击打开Main. ...

随机推荐

  1. SQL 在表中随机取数据

    在一张10万行产品表(Product)中,随机取10条数据的几种方式: SET STATISTICS IO ON SELECT TOP 10 ID FROM dbo.Product(NOLOCK) W ...

  2. 修复 Java 内存模型,第 2 部分——Brian Goetz

    转自Java并发大师Brain Goetz:http://www.ibm.com/developerworks/cn/java/j-jtp03304/ (中文地址) http://www.ibm.co ...

  3. UVA 11355 Cool Points(几何)

    Cool Points We have a circle of radius R and several line segments situated within the circumference ...

  4. A daemon process class in python

    In everbright task schedule project, we need some daemon process to do certain work, here is a examp ...

  5. Linux 下子线程 exit code 在主线程中的使用

    Linux线程函数原型是这样的: void* thread_fun(void* arg) 它的返回值是 空类型指针,入口参数也是 空类型指针.那么线程的 exit code 也应该是 void * 类 ...

  6. gnuplot 学习笔记

    1 如何运行 gnuplot是一个命令行输入的工具,把命令行写入一个文本file1 file2.使用下列方式运行. gnuplot {option} file1 file2 2 产生一个图标,不管数据 ...

  7. 怎样用好ZBrush中的PaintStop插件

    PaintStop是ZBrush®3.1的手绘插件,可以比较真实的模拟手绘风格,尤其是用水彩笔刷画水墨风格画.PaintStop插件可供用户免费使用. PaintStop是一款功能强大的插件,已经被添 ...

  8. 分享用于学习C++图像处理的代码示例

    为了便于学习图像处理并研究图像算法, 俺写了一个适合初学者学习的小小框架. 麻雀虽小五脏俱全. 采用的加解码库:stb_image 官方:http://nothings.org/ stb_image. ...

  9. python-可变迭代对象在for循环中的风险Risk in FOR loop while looping mutable iterable object

    >>> a = [1,2,3,4,5,6] >>> for item in a: ... a.remove(item) ... >>> a [2, ...

  10. HDU 5047 推公式+别样输出

    题意:给n个‘M'形,问最多能把平面分成多少区域 解法:推公式 : f(n) = 4n(4n+1)/2 - 9n + 1 = (8n+1)(n-1)+2 前面部分有可能超long long,所以要转化 ...