三. 创建文件夹

问题:

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

解决方案:

使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. IOS 应用跳转 (IOS9白名单)

    跳转到指定app的实现 IOS中应用的跳转是通过URL实现的,因此在实现应用跳转之前我们要设置一下对应的URL. 图一(寻找配置软件的URL) 图二(具体配置选项) 注意: 如果IOS版本为IOS9 ...

  2. UIViewController的edgesForExtendedLayout属性

    UIViewController的edgesForExtendedLayout属性 想必大家都遇到一种情况,明明y坐标设置的是0,但是总是被讨厌的导航栏给遮住.比如下面这个情况: UILabel *l ...

  3. onmousedown,onmouseup,onclick同时应用于一个标签节点Element

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  4. APP国际化

    1.app本地内容国际化 ①在项目中新建一个New File ---> iOS Resource -> String File ---> 命名为Localizable(之所以命名为L ...

  5. Autocomplete:属性介绍、firefox中文支持问题

    如有问题,请前往 http://www.cnblogs.com/dreamowneryong/p/4953911.html 原文评论交流 一,属性介绍 * minChars (Number) 在触发a ...

  6. 【mysql】使用tpcc-mysql进行压力测试

    Tpcc-mysql是percona基于tpcc衍生出来专用于mysql基准测试的产品 ,可以参见 <高性能MySQL第三版> 一.安装 rpm -Uvh http://dl.fedora ...

  7. MYSQL界面操作系统之phpMyAdmin

    linux下: 需要PHP环境支持,安装PHP自行百度 下载linux-phpMyAdmin,并解压 php -S 127.0.0.1:8081 -t phpMyAdmin/

  8. C#操作XML小结(转)

    一.简单介绍 using System.Xml; //初始化一个xml实例 XmlDocument xml=new XmlDocument(); //导入指定xml文件 xml.Load(path); ...

  9. 如何使用emacs编写c语言程序,并编译运行

    vi和emacs被分别被称为编辑器之神和神之编辑器.vi的入门精通都很难,emacs入门容易,精通难:vi使用起来不停地切换模式,而emacs则不停地ctrl,meta等组合键.因此,高德纳大师说操作 ...

  10. HTable和HTablePool使用注意事项

    HTable和HTablePool都是HBase客户端API的一部分,可以使用它们对HBase表进行CRUD操作.下面结合在项目中的应用情况,对二者使用过程中的注意事项做一下概括总结. HTable ...