三. 创建文件夹

问题:

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

解决方案:

使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. UITableVIew 滚动流畅性优化

    影响UITableViewUITableView滚动的流畅性原因: 1. 在代理方法中做了过多的计算占用了 UI 线程的时间 2.同上 3.Cell 中 view 的组织复杂,比如使用layer并不会 ...

  2. IT技术很好的视频网址

    1.华为工程师 带你实战C++ 2.vimoe,国外的,需要FQ哦.https://vimeo.com/85831438

  3. Java眼中的XML--文件读取--1 应用DOM方式解析XML

    初次邂逅XML: 需要解析的XML文件: 这里有两个book子节点. 1.如何进行XML文件解析前的准备工作,另外解析先获取book节点. 这个我后来看懂了: 这个Node的ELEMENT_NODE= ...

  4. eclipse 导入新项目后报错:Cannot change version of project facet Dynamic web module to 2.5

    错误原因: 我们用Eclipse创建Maven结构的web项目的时候选择了Artifact Id为maven-artchetype-webapp,由于这个catalog比较老,用的servlet还是2 ...

  5. [LoadRunner]性能测试实践_Hessian协议脚本编写

    第一步,新建LR的脚本,选择Java Vuser协议: 第二步,编写hessian测试脚本,如下: import lrapi.lr; import java.net.MalformedURLExcep ...

  6. Effective Java 15 Minimize mutability

    Use immutable classes as much as possible instead of mutable classes. Advantage Easy to design, impl ...

  7. LightSpeed使用指南

    LightSpeed 是一个最高性能的 .NET 领域建模和 O/R 映射框架,第一级别的 LINQ 支持.Visual Studio 2008/2010 设计器集成,是一个著名的高性能框架.[注:收 ...

  8. Tomcat报java.lang.ClassNotFoundException: 1catalina.org.apache.juli.FileHandler

    最近在生产环境部署Tomcat的时候,在启动的时候,在控制台报"java.lang.ClassNotFoundException: 1catalina.org.apache.juli.Fil ...

  9. python lambda表达式简单用法

    习条件运算时,对于简单的 if else 语句,可以使用三元运算来表示,即: 1 2 3 4 5 6 7 8 # 普通条件语句 if 1 == 1:     name = 'wupeiqi' else ...

  10. jquery发送异步请求

    var remark = $("#"+id+"remark").val(); var shopid = $("#"+id+"sho ...